From 3ece4f0b7bedb64d85cf51b8217bc5dd09968b92 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 4 Jul 2025 16:02:32 -0500 Subject: [PATCH] chore: move all files to file-scoped namespace --- src/PepperDash.Core/ComTextHelper.cs | 43 - .../Comm/CommunicationGather.cs | 85 +- .../Comm/CommunicationStreamDebugging.cs | 269 +- .../Comm/ControlPropertiesConfig.cs | 141 +- src/PepperDash.Core/Comm/EventArgs.cs | 379 +- .../Comm/GenericSecureTcpIpClient.cs | 1745 ++++---- .../GenericSecureTcpIpClient_ForServer.cs | 1613 ++++---- .../Comm/GenericSecureTcpIpServer.cs | 1739 ++++---- src/PepperDash.Core/Comm/GenericSshClient.cs | 1090 +++-- .../Comm/GenericTcpIpClient.cs | 807 ++-- .../Comm/GenericTcpIpClient_ForServer.cs | 1366 ++++--- .../Comm/GenericTcpIpServer.cs | 1683 ++++---- src/PepperDash.Core/Comm/GenericUdpServer.cs | 706 ++-- .../Comm/TcpClientConfigObject.cs | 91 +- .../Comm/TcpServerConfigObject.cs | 99 +- src/PepperDash.Core/Comm/eControlMethods.cs | 153 +- .../Comm/eStreamDebuggingSetting.cs | 28 - src/PepperDash.Core/CommunicationExtras.cs | 322 +- .../Config/PortalConfigReader.cs | 91 +- src/PepperDash.Core/Conversion/Convert.cs | 32 +- src/PepperDash.Core/CoreInterfaces.cs | 42 +- src/PepperDash.Core/Device.cs | 352 +- src/PepperDash.Core/EthernetHelper.cs | 13 +- src/PepperDash.Core/EventArgs.cs | 7 +- .../GenericRESTfulCommunications/Constants.cs | 9 +- .../GenericRESTfulClient.cs | 13 +- .../EventArgs and Constants.cs | 7 +- .../JsonStandardObjects/JsonToSimplDevice.cs | 7 +- .../JsonToSimplDeviceConfig.cs | 205 +- src/PepperDash.Core/JsonToSimpl/Constants.cs | 165 +- src/PepperDash.Core/JsonToSimpl/Global.cs | 18 +- .../JsonToSimplArrayLookupChild.cs | 32 +- .../JsonToSimpl/JsonToSimplChildObjectBase.cs | 209 +- .../JsonToSimpl/JsonToSimplFileMaster.cs | 482 ++- .../JsonToSimpl/JsonToSimplFixedPathObject.cs | 19 +- .../JsonToSimpl/JsonToSimplGenericMaster.cs | 31 +- .../JsonToSimpl/JsonToSimplMaster.cs | 92 +- .../JsonToSimplPortalFileMaster.cs | 31 +- .../Logging/CrestronEnricher.cs | 49 +- src/PepperDash.Core/Logging/Debug.cs | 5 +- .../Logging/DebugConsoleSink.cs | 67 +- src/PepperDash.Core/Logging/DebugContext.cs | 497 ++- .../Logging/DebugCrestronLoggerSink.cs | 39 +- .../Logging/DebugErrorLogSink.cs | 87 +- .../Logging/DebugExtensions.cs | 146 +- src/PepperDash.Core/Logging/DebugMemory.cs | 111 +- .../Logging/DebugWebsocketSink.cs | 4 - .../Network/DiscoveryThings.cs | 18 +- .../PasswordManagement/Config.cs | 7 +- .../PasswordManagement/Constants.cs | 7 +- .../PasswordManagement/PasswordClient.cs | 13 +- .../PasswordManagement/PasswordManager.cs | 15 +- .../SystemInfo/EventArgs and Constants.cs | 103 +- .../SystemInfo/SystemInfoConfig.cs | 211 +- .../SystemInfo/SystemInfoToSimpl.cs | 49 +- src/PepperDash.Core/Web/BouncyCertificate.cs | 650 ++- .../RequestHandlers/DefaultRequestHandler.cs | 13 +- .../WebApiBaseRequestAsyncHandler.cs | 292 +- .../WebApiBaseRequestHandler.cs | 7 +- src/PepperDash.Core/Web/WebApiServer.cs | 7 +- src/PepperDash.Core/WebApi/Presets/Preset.cs | 93 +- src/PepperDash.Core/WebApi/Presets/User.cs | 83 +- .../WebApi/Presets/WebApiPasscodeClient.cs | 194 +- .../Serialization/IXSigSerialization.cs | 33 +- .../XSigSerializationException.cs | 39 +- .../XSigUtility/Tokens/XSigAnalogToken.cs | 155 +- .../XSigUtility/Tokens/XSigDigitalToken.cs | 149 +- .../XSigUtility/Tokens/XSigSerialToken.cs | 136 +- .../XSigUtility/Tokens/XSigToken.cs | 77 +- .../XSigUtility/Tokens/XSigTokenType.cs | 33 +- .../XSigUtility/XSigHelpers.cs | 461 +-- .../XSigUtility/XSigTokenStreamReader.cs | 248 +- .../XSigUtility/XSigTokenStreamWriter.cs | 246 +- .../Bridges/BridgeBase.cs | 811 ++-- .../Bridges/BridgeHelper.cs | 107 +- .../Bridges/IBridge.cs | 22 +- .../JoinMaps/AirMediaControllerJoinMap.cs | 164 +- .../Bridges/JoinMaps/AppleTvJoinMap.cs | 111 +- .../JoinMaps/C2nRthsControllerJoinMap.cs | 89 +- .../JoinMaps/CameraControllerJoinMap.cs | 192 +- .../CenOdtOccupancySensorBaseJoinMap.cs | 498 +-- .../JoinMaps/DisplayControllerJoinMap.cs | 199 +- .../DmBladeChassisControllerJoinMap.cs | 174 +- .../JoinMaps/DmChassisControllerJoinMap.cs | 410 +- .../JoinMaps/DmRmcControllerJoinMap.cs | 216 +- .../Bridges/JoinMaps/DmTxControllerJoinMap.cs | 227 +- .../DmpsAudioOutputControllerJoinMap.cs | 443 +-- .../DmpsMicrophoneControllerJoinMap.cs | 103 +- .../JoinMaps/DmpsRoutingControllerJoinMap.cs | 289 +- .../JoinMaps/GenericIrControllerJoinMap.cs | 10 +- .../JoinMaps/GenericLightingJoinMap.cs | 95 +- .../JoinMaps/GenericRelayControllerJoinMap.cs | 49 +- .../JoinMaps/GlsOccupancySensorBaseJoinMap.cs | 474 +-- .../JoinMaps/GlsPartitionSensorJoinMap.cs | 315 +- .../JoinMaps/HdMdNxM4kEControllerJoinMap.cs | 146 +- .../JoinMaps/HdMdxxxCEControllerJoinMap.cs | 171 +- .../JoinMaps/HdPsXxxControllerJoinMap.cs | 10 +- .../Hrxxx0WirelessRemoteControllerJoinMap.cs | 641 ++- .../Bridges/JoinMaps/IAnalogInputJoinMap.cs | 59 +- .../JoinMaps/IBasicCommunicationJoinMap.cs | 102 +- .../Bridges/JoinMaps/IDigitalInputJoinMap.cs | 48 +- .../Bridges/JoinMaps/IDigitalOutputJoinMap.cs | 48 +- .../Bridges/JoinMaps/IRBlurayBaseJoinMap.cs | 559 +-- .../Bridges/JoinMaps/PduJoinMapBase.cs | 130 +- .../JoinMaps/SetTopBoxControllerJoinMap.cs | 621 ++- .../JoinMaps/StatusSignControllerJoinMap.cs | 128 +- .../Bridges/JoinMaps/SystemMonitorJoinMap.cs | 330 +- .../JoinMaps/VideoCodecControllerJoinMap.cs | 1352 +++---- .../Comm and IR/CecPortController.cs | 246 +- .../Comm and IR/ComPortController.cs | 148 +- .../Comm and IR/ComSpecJsonConverter.cs | 176 +- .../Comm and IR/CommFactory.cs | 224 +- .../Comm and IR/CommunicationExtras.cs | 7 +- .../Comm and IR/ConsoleCommMockDevice.cs | 43 +- .../Comm and IR/GenericComm.cs | 232 +- .../Comm and IR/GenericHttpClient.cs | 27 +- .../Comm and IR/IRPortHelper.cs | 121 +- .../Config/AudioControlPointListItem.cs | 24 +- .../Config/BasicConfig.cs | 160 +- .../Config/ConfigPropertiesHelpers.cs | 30 +- .../Config/DeviceConfig.cs | 153 +- .../Config/Essentials/ConfigReader.cs | 259 +- .../Config/Essentials/ConfigUpdater.cs | 367 +- .../Config/Essentials/ConfigWriter.cs | 268 +- .../Config/Essentials/EssentialsConfig.cs | 274 +- .../Config/ILoadConfig.cs | 15 +- .../Config/InfoConfig.cs | 100 +- .../SourceDevicePropertiesConfigBase.cs | 18 +- .../Crestron/CrestronGenericBaseDevice.cs | 223 +- .../CrestronIO/GenericRelayDevice.cs | 424 +- .../GenericVersiportAnalogInputDevice.cs | 4 +- .../CrestronIO/GenericVersiportInputDevice.cs | 4 +- .../GenericVersiportOutputDevice.cs | 243 +- .../CrestronIO/IAnalogInput.cs | 4 +- .../CrestronIO/IDigitalInput.cs | 25 +- .../CrestronIO/IDigitalOutput.cs | 7 +- .../CrestronIO/IHasCresnetBranches.cs | 7 +- .../CrestronIO/IOPortConfig.cs | 1 - .../CrestronIO/ISwitchedOutput.cs | 53 +- .../Device Info/DeviceInfo.cs | 51 +- .../Device Info/DeviceInfoEventArgs.cs | 48 +- .../Device Info/IDeviceInfoProvider.cs | 44 +- .../Device Info/NetworkDeviceHelpers.cs | 368 +- .../DeviceTypeInterfaces/IChannel.cs | 7 +- .../DeviceTypeInterfaces/IColorFunctions.cs | 7 +- .../DeviceTypeInterfaces/IDPad.cs | 7 +- .../IDiscPlayerControls.cs | 7 +- .../DeviceTypeInterfaces/IDisplay.cs | 21 +- .../DeviceTypeInterfaces/IDisplayBasic.cs | 6 +- .../DeviceTypeInterfaces/IDumbSource.cs | 13 +- .../DeviceTypeInterfaces/IDvr.cs | 7 +- .../DeviceTypeInterfaces/IEmergencyOSD.cs | 33 +- .../DeviceTypeInterfaces/IHasBranding.cs | 29 +- .../IHasFarEndContentStatus.cs | 20 +- .../DeviceTypeInterfaces/IHasInputs.cs | 27 +- .../DeviceTypeInterfaces/IHasPhoneDialing.cs | 65 +- .../IHasScreensWithLayouts.cs | 185 +- .../IHasSurroundSoundModes.cs | 5 - .../DeviceTypeInterfaces/IHasWebView.cs | 143 +- .../DeviceTypeInterfaces/IHumiditySensor.cs | 7 +- .../ILanguageDefinition.cs | 83 +- .../DeviceTypeInterfaces/ILanguageProvider.cs | 29 +- .../DeviceTypeInterfaces/ILevelControls.cs | 19 +- .../DeviceTypeInterfaces/IMobileControl.cs | 111 +- .../DeviceTypeInterfaces/IPasswordPrompt.cs | 101 +- .../DeviceTypeInterfaces/IPower.cs | 131 +- .../IProjectorScreenLiftControl.cs | 7 +- .../DeviceTypeInterfaces/ISelectableItem.cs | 40 +- .../DeviceTypeInterfaces/ISelectableItems.cs | 63 +- .../ISetTopBoxControls.cs | 7 +- .../ITemperatureSensor.cs | 43 +- .../DeviceTypeInterfaces/ITransport.cs | 175 +- .../ITvPresetsProvider.cs | 19 +- .../DeviceTypeInterfaces/IUiDisplayInfo.cs | 7 +- .../DeviceTypeInterfaces/IWarmingCooling.cs | 7 +- .../DeviceTypeInterfaces/LanguageLabel.cs | 46 +- .../DeviceTypeInterfaces/Template.cs | 7 +- .../Devices/AudioControlListItemBase.cs | 59 +- .../Devices/AudioInterfaces.cs | 7 +- .../Devices/CameraListItem.cs | 142 +- .../Devices/CodecInterfaces.cs | 183 +- .../Devices/CrestronProcessor.cs | 71 +- .../Devices/DestinationListItem.cs | 227 +- .../Devices/DeviceApiBase.cs | 27 +- .../Devices/DeviceFeedbackExtensions.cs | 37 +- .../Devices/DeviceJsonApi.cs | 958 ++--- .../Devices/DisplayUiConstants.cs | 7 +- .../Devices/EssentialsBridgeableDevice.cs | 34 +- .../Devices/EssentialsDevice.cs | 364 +- .../Devices/EssentialsDeviceFactory.cs | 42 +- .../Devices/GenericIRController.cs | 188 +- .../Devices/GenericMonitoredTcpDevice.cs | 9 +- .../Devices/IAttachVideoStatusExtensions.cs | 59 +- .../Devices/IHasFeedbacks.cs | 54 +- .../Devices/IProjectorInterfaces.cs | 57 +- .../Devices/IReconfigurableDevice.cs | 38 +- .../Devices/IUsageTracking.cs | 192 +- .../Devices/IrOutputPortController.cs | 353 +- .../Devices/LevelControlListItem.cs | 206 +- .../Devices/PduInterfaces.cs | 47 +- .../Devices/PowerInterfaces.cs | 247 +- .../Devices/PresentationDeviceType.cs | 13 +- .../Devices/PresetListItem.cs | 63 +- .../Devices/ReconfigurableDevice.cs | 134 +- .../Devices/SmartObjectBaseTypes.cs | 37 +- .../Devices/SourceListItem.cs | 540 ++- .../Devices/VolumeDeviceChangeEventArgs.cs | 10 +- .../eSourceListItemDestinationTypes.cs | 94 + .../Ethernet/EthernetStatistics.cs | 79 +- .../Extensions/IpAddressExtensions.cs | 131 +- .../Extensions/JsonExtensions.cs | 64 +- .../Extensions/StringExtensions.cs | 125 +- .../Factory/IDeviceFactory.cs | 39 +- .../IProcessorExtensionDeviceFactory.cs | 19 +- .../ProcessorExtensionDeviceFactory.cs | 6 +- .../Factory/ReadyEventArgs.cs | 62 +- .../Feedbacks/BoolFeedback.cs | 330 +- .../Feedbacks/BoolFeedbackOneShot.cs | 39 +- .../Feedbacks/BoolFeedbackPulseExtender.cs | 7 +- .../Feedbacks/BoolOutputLogicals.cs | 9 +- .../Feedbacks/FeedbackBase.cs | 7 +- .../Feedbacks/FeedbackCollection.cs | 21 +- .../Feedbacks/FeedbackEventArgs.cs | 159 +- .../Feedbacks/IntFeedback.cs | 200 +- .../Feedbacks/SerialFeedback.cs | 157 +- .../Feedbacks/StringFeedback.cs | 194 +- src/PepperDash.Essentials.Core/File/FileIO.cs | 133 +- ...entialsHuddleSpaceRoomFusionRoomJoinMap.cs | 434 +- .../Fusion/FusionCustomPropertiesBridge.cs | 186 +- .../Fusion/FusionEventHandlers.cs | 5 +- .../Fusion/FusionProcessorQueries.cs | 98 +- .../Fusion/FusionRviDataClasses.cs | 1170 ++---- .../Global/EthernetAdapterInfo.cs | 100 +- .../Global/Global.cs | 344 +- .../Global/JobTimer.cs | 9 +- .../Global/Scheduler.cs | 550 ++- .../InUseTracking/IInUseTracking.cs | 7 +- .../InUseTracking/InUseTracking.cs | 7 +- .../Interfaces/ILogStrings.cs | 21 +- .../Interfaces/ILogStringsWithLevel.cs | 22 +- .../JoinMaps/JoinMapBase.cs | 988 ++--- .../License/EssentialsLicenseManager.cs | 175 +- .../Lighting/Lighting Interfaces.cs | 188 +- .../MicrophonePrivacyController.cs | 429 +- .../MicrophonePrivacyControllerConfig.cs | 8 +- ...CrestronGenericBaseCommunicationMonitor.cs | 7 +- .../Monitoring/GenericCommunicationMonitor.cs | 616 ++- .../Monitoring/StatusMonitorBase.cs | 36 +- .../Monitoring/StatusMonitorCollection.cs | 7 +- .../Monitoring/SystemMonitorController.cs | 1952 +++++---- .../EssentialsPartitionController.cs | 358 +- .../IPartitionStateProvider.cs | 102 +- .../Plugins/IPluginDeviceFactory.cs | 32 +- .../Plugins/PluginLoader.cs | 21 +- .../Presets/DevicePresets.cs | 598 ++- .../Presets/DevicePresetsView.cs | 149 +- .../Presets/PresetChannel.cs | 77 +- .../PresetsListSubpageReferenceListItem.cs | 10 +- .../Queues/ComsMessage.cs | 116 +- .../Queues/GenericQueue.cs | 524 ++- .../Queues/IQueue.cs | 29 +- .../Queues/IQueueMessage.cs | 20 +- .../Queues/ProcessStringMessage.cs | 72 +- .../Queues/StringResponseProcessor.cs | 181 +- .../Ramps and Increments/ActionIncrementer.cs | 210 +- .../Ramps and Increments/NumericalHelpers.cs | 61 +- .../UshortSigIncrementer.cs | 186 +- .../RoomOnToDefaultSourceWhenOccupied.cs | 1008 +++-- .../Room/Combining/EssentialsRoomCombiner.cs | 844 ++-- .../EssentialsRoomCombinerPropertiesConfig.cs | 59 +- ...sentialsDualDisplayRoomPropertiesConfig.cs | 15 +- .../EssentialsHuddleRoomPropertiesConfig.cs | 49 +- .../EssentialsHuddleVtc1PropertiesConfig.cs | 23 +- .../EssentialsNDisplayRoomPropertiesConfig.cs | 90 +- .../Room/Config/EssentialsRoomConfig.cs | 843 ++-- .../Config/EssentialsRoomEmergencyConfig.cs | 53 +- .../EssentialsRoomScheduledEventsConfig.cs | 112 +- .../Room/Config/EssentialsTechRoomConfig.cs | 156 +- .../Config/EssentialsVolumeLevelConfig.cs | 128 +- .../Room/Config/SimplRoomPropertiesConfig.cs | 89 +- .../EsentialsRoomEmergencyContactClosure.cs | 162 +- .../Room/EssentialsRoomBase.cs | 864 ++-- .../Room/IEssentialsRoom.cs | 158 +- .../Room/IRoomEventSchedule.cs | 59 +- .../Room/Interfaces.cs | 489 +-- src/PepperDash.Essentials.Core/Room/Room.cs | 19 +- .../Room/iOccupancyStatusProvider.cs | 20 +- .../Routing/DummyRoutingInputsDevice.cs | 57 +- .../Routing/Extensions.cs | 787 ++-- .../Routing/IHasCurrentSourceInfoChange.cs | 13 +- .../Routing/IInputSync.cs | 4 - .../Routing/IRmcRouting.cs | 20 +- .../Routing/IRmcRoutingWithFeedback.cs | 13 +- .../Routing/IRouting.cs | 29 +- .../Routing/IRoutingFeedback.cs | 22 +- .../IRoutingHasVideoInputSyncFeedbacks.cs | 7 +- .../Routing/IRoutingInputSlot.cs | 19 +- .../Routing/IRoutingInputs.cs | 23 +- .../Routing/IRoutingInputsOutputs.cs | 23 +- .../Routing/IRoutingNumeric.cs | 26 +- .../Routing/IRoutingNumericWithFeedback.cs | 13 +- .../Routing/IRoutingOutputSlot.cs | 35 +- .../Routing/IRoutingOutputs.cs | 24 +- .../Routing/IRoutingSink.cs | 46 +- .../Routing/IRoutingSinkWithFeedback.cs | 29 +- .../Routing/IRoutingSinkWithSwitching.cs | 59 +- .../Routing/IRoutingSlot.cs | 5 - .../Routing/IRoutingSource.cs | 13 +- .../Routing/IRoutingWithClear.cs | 21 +- .../Routing/IRoutingWithFeedback.cs | 45 +- .../Routing/ITxRouting.cs | 26 +- .../Routing/ITxRoutingWithFeedback.cs | 13 +- .../Routing/RouteDescriptor.cs | 358 +- .../Routing/RouteDescriptorCollection.cs | 168 +- .../Routing/RouteRequest.cs | 123 +- .../Routing/RouteRequestQueueItem.cs | 145 +- .../Routing/RouteSwitchDescriptor.cs | 65 +- .../Routing/RoutingFeedbackManager.cs | 594 ++- .../Routing/RoutingInputPort.cs | 72 +- .../RoutingInputPortWithVideoStatuses.cs | 54 +- .../Routing/RoutingNumericEventArgs.cs | 137 +- .../Routing/RoutingOutputPort.cs | 144 +- .../Routing/RoutingPort.cs | 68 +- .../Routing/RoutingPortCollection.cs | 22 +- .../Routing/RoutingPortNames.cs | 423 +- .../Routing/TieLine.cs | 270 +- .../Routing/TieLineConfig.cs | 7 +- .../Routing/eRoutingPortConnectionType.cs | 2 +- .../Routing/eRoutingSignalType.cs | 2 +- .../Secrets/CrestronGlobalSecretsProvider.cs | 190 +- .../Secrets/CrestronLocalSecretsProvider.cs | 192 +- .../Secrets/CrestronSecret.cs | 48 +- .../Secrets/Interfaces.cs | 93 +- .../Secrets/SecretsManager.cs | 692 ++-- .../Secrets/SecretsPropertiesConfig.cs | 28 +- .../Shades/Shade Interfaces.cs | 303 +- .../Shades/ShadeBase.cs | 66 +- src/PepperDash.Essentials.Core/SigHelper.cs | 7 +- .../SmartObjects/SmartObjectDPad.cs | 71 +- .../SmartObjects/SmartObjectDynamicList.cs | 261 +- .../SmartObjects/SmartObjectHelperBase.cs | 163 +- .../SmartObjects/SmartObjectNumeric.cs | 170 +- .../SubpageReferenceList.cs | 515 ++- .../SubpageReferenceListItem.cs | 81 +- .../Timers/CountdownTimer.cs | 290 +- .../Timers/RetriggerableTimer.cs | 312 +- .../CrestronTouchpanelPropertiesConfig.cs | 195 +- .../Touchpanels/Interfaces.cs | 27 +- .../Keyboards/HabaneroKeyboardController.cs | 790 ++-- .../Touchpanels/ModalDialog.cs | 120 +- .../Touchpanels/Mpc3Touchpanel.cs | 85 +- .../Touchpanels/TriListExtensions.cs | 119 +- .../TriListBridges/HandlerBridge.cs | 42 +- .../UI PageManagers/BlurayPageManager.cs | 11 +- .../UI PageManagers/PageManager.cs | 7 +- .../SetTopBoxThreePanelPageManager.cs | 405 +- .../SetTopBoxTwoPanelPageManager.cs | 7 +- .../UI PageManagers/SinglePageManager.cs | 7 +- .../UI/TouchpanelBase.cs | 268 +- .../Utilities/ActionSequence.cs | 250 +- .../VideoStatus/VideoStatusOutputs.cs | 7 +- .../Web/EssentialsWebApi.cs | 505 ++- .../Web/EssentialsWebApiFactory.cs | 47 +- .../Web/EssentialsWebApiHelpers.cs | 184 +- .../Web/EssentialsWebApiPropertiesConfig.cs | 19 +- .../RequestHandlers/AppDebugRequestHandler.cs | 156 +- .../DebugSessionRequestHandler.cs | 165 +- .../Web/RequestHandlers/DebugWebsocketSink.cs | 63 +- .../RequestHandlers/DefaultRequestHandler.cs | 10 +- .../RequestHandlers/DevJsonRequestHandler.cs | 48 +- .../RequestHandlers/DevListRequestHandler.cs | 80 +- .../DevMethodsRequestHandler.cs | 133 +- .../RequestHandlers/DevPropsRequestHandler.cs | 131 +- .../DisableAllStreamDebugRequestHandler.cs | 48 +- ...DoNotLoadConfigOnNextBootRequestHandler.cs | 150 +- .../GetFeedbacksForDeviceRequestHandler.cs | 172 +- .../GetJoinMapForBridgeKeyRequestHandler.cs | 128 +- .../GetJoinMapForDeviceKeyRequestHandler.cs | 168 +- .../Web/RequestHandlers/GetRoutesHandler.cs | 98 +- .../RequestHandlers/GetRoutingPortsHandler.cs | 125 +- .../GetTieLinesRequestHandler.cs | 55 +- .../GetTypesByFilterRequestHandler.cs | 117 +- .../RequestHandlers/GetTypesRequestHandler.cs | 97 +- .../LoadConfigRequestHandler.cs | 68 +- .../ReportVersionsRequestHandler.cs | 79 +- .../RestartProgramRequestHandler.cs | 64 +- .../SetDeviceStreamDebugRequestHandler.cs | 420 +- .../ShowConfigRequestHandler.cs | 59 +- .../Audio/GenericAudioOut.cs | 240 +- .../AudioCodec/AudioCodecBase.cs | 189 +- .../AudioCodec/Interfaces/IAudioCodecInfo.cs | 38 +- .../AudioCodec/Interfaces/IHasAudioCodec.cs | 19 +- .../AudioCodec/MockAC/MockAC.cs | 240 +- .../MockAC/MockAcPropertiesConfig.cs | 17 +- .../Cameras/CameraBase.cs | 557 ++- .../Cameras/CameraVisca.cs | 1331 +++---- .../Cameras/IHasCameraPresets.cs | 50 +- .../Codec/Cisco/IPresenterTrack.cs | 139 +- .../Codec/Cisco/ISpeakerTrack.cs | 49 +- .../Codec/CodecActiveCallItem.cs | 175 +- .../Codec/IHasCallHold.cs | 30 +- .../Codec/IHasDoNotDisturb.cs | 67 +- .../Codec/IHasExternalSourceSwitching.cs | 82 +- .../Codec/eCodecCallDirection.cs | 92 +- .../Codec/eCodecCallStatus.cs | 255 +- .../Codec/eCodecCallType.cs | 125 +- .../Codec/eMeetingPrivacy.cs | 89 +- .../Codec/iCodecAudio.cs | 15 +- .../Codec/iHasCallFavorites.cs | 48 +- .../Codec/iHasCallHistory.cs | 259 +- .../Codec/iHasContentSharing.cs | 52 +- .../Codec/iHasDialer.cs | 89 +- .../DSP/DspBase.cs | 260 +- .../Displays/BasicIrDisplay.cs | 526 +-- .../Displays/DisplayBase.cs | 721 ++-- .../Displays/InputInterfaces.cs | 130 +- .../Displays/MockDisplay.cs | 591 ++- .../Displays/MockDisplayInputs.cs | 184 +- .../Displays/ScreenLiftController.cs | 4 +- .../Generic/GenericSink.cs | 224 +- .../Generic/GenericSource.cs | 127 +- .../Lighting/LightingBase.cs | 266 +- .../Room/IEssentialsHuddleSpaceRoom.cs | 39 +- .../Room/IEssentialsHuddleVtc1Room.cs | 76 +- .../Room/IEssentialsRoomPropertiesConfig.cs | 19 +- .../Room/IEssentialsTechRoom.cs | 49 +- .../SetTopBox/IRSetTopBoxBase.cs | 2 +- .../SetTopBox/SetTopBoxPropertiesConfig.cs | 59 +- .../Shades/RelayControlledShade.cs | 306 +- .../Shades/ShadeBase.cs | 59 +- .../Shades/ShadeController.cs | 161 +- .../SoftCodec/BlueJeansPc.cs | 331 +- .../SoftCodec/GenericSoftCodec.cs | 238 +- .../Sources/InRoomPc.cs | 121 +- .../Sources/Laptop.cs | 131 +- .../Streaming/AppleTV.cs | 462 +-- .../CiscoCodec/CallHistoryDataClasses.cs | 420 +- .../VideoCodec/CiscoCodec/RoomPresets.cs | 137 +- .../VideoCodec/CiscoCodec/eCommandType.cs | 7 +- .../CiscoCodec/eExternalSourceMode.cs | 2 +- .../CiscoCodec/eExternalSourceType.cs | 2 +- .../VideoCodec/ConvertiblePreset.cs | 22 +- .../VideoCodec/Interfaces/IHasCodecLayouts.cs | 43 +- .../Interfaces/IHasCodecSelfview.cs | 52 +- .../VideoCodec/Interfaces/IHasMeetingInfo.cs | 28 +- .../VideoCodec/Interfaces/IHasMeetingLock.cs | 43 +- .../Interfaces/IHasMeetingRecording.cs | 44 +- .../VideoCodec/Interfaces/IHasParticipants.cs | 2 +- .../Interfaces/IHasPresentationOnlyMeeting.cs | 103 +- .../Interfaces/IHasSelfviewPosition.cs | 36 +- .../VideoCodec/Interfaces/IHasSelfviewSize.cs | 35 +- .../VideoCodec/Interfaces/IHasStandbyMode.cs | 72 +- .../VideoCodec/Interfaces/IHasStartMeeting.cs | 35 +- .../VideoCodec/Interfaces/IHasVideoCodec.cs | 33 +- .../VideoCodec/Interfaces/IJoinCalls.cs | 30 +- .../VideoCodec/MockVC/MockVCCamera.cs | 433 +- .../MockVC/MockVcPropertiesConfig.cs | 48 +- .../VideoCodec/VideoCodecBase.cs | 3537 ++++++++--------- .../ContentTypes.cs | 14 +- .../DisplayBaseMessenger.cs | 9 +- .../DeviceTypeExtensions/IChannelMessenger.cs | 7 + .../DeviceTypeExtensions/IColorMessenger.cs | 8 + .../DeviceTypeExtensions/IDPadMessenger.cs | 9 +- .../DeviceTypeExtensions/IDvrMessenger.cs | 12 +- .../IHasPowerMessenger.cs | 9 + .../DeviceTypeExtensions/INumericMessenger.cs | 9 + .../ISetTopBoxControlsMessenger.cs | 15 +- .../ITransportMessenger.cs | 11 +- .../Messengers/DeviceInfoMessenger.cs | 5 +- .../Messengers/DeviceVolumeMessenger.cs | 21 +- .../Messengers/GenericMessenger.cs | 2 +- .../ICommunicationMonitorMessenger.cs | 2 +- .../Messengers/IDspPresetsMessenger.cs | 14 +- .../IEssentialsRoomCombinerMessenger.cs | 2 +- .../IHasCurrentSourceInfoMessenger.cs | 2 +- .../Messengers/IHasInputsMessenger.cs | 12 +- .../IHasPowerControlWithFeedbackMessenger.cs | 2 +- .../IHasScheduleAwarenessMessenger.cs | 156 +- .../Messengers/IHumiditySensor.cs | 9 +- .../Messengers/ILevelControlsMessenger.cs | 17 +- .../Messengers/IMatrixRoutingMessenger.cs | 84 +- .../IProjectorScreenLiftControlMessenger.cs | 2 +- .../Messengers/ISelectableItemsMessenger.cs | 2 +- .../IShutdownPromptTimerMessenger.cs | 9 +- .../Messengers/ISwitchedOutputMessenger.cs | 10 +- .../Messengers/ITechPasswordMessenger.cs | 19 +- .../Messengers/ITemperatureSensorMessenger.cs | 10 +- .../Messengers/LightingBaseMessenger.cs | 8 + .../Messengers/MessengerBase.cs | 2 +- .../Messengers/PressAndHoldHandler.cs | 2 +- .../Messengers/RoomEventScheduleMessenger.cs | 167 +- .../Messengers/ShadeBaseMessenger.cs | 14 + .../Messengers/SystemMonitorMessenger.cs | 1 + .../Messengers/TwoWayDisplayBaseMessenger.cs | 7 + .../MobileControlMessage.cs | 8 +- .../MobileControlSimpleContent.cs | 22 +- .../SIMPLJoinMaps/SIMPLVtcJoinMap.cs | 3 +- .../AuthorizationResponse.cs | 59 +- .../MobileControlAction.cs | 47 +- .../MobileControlDeviceFactory.cs | 44 +- .../MobileControlEssentialsConfig.cs | 119 +- .../MobileControlSystemController.cs | 2 +- .../RoomBridges/MobileControlBridgeBase.cs | 293 +- .../Services/MobileControlApiService.cs | 121 +- .../Touchpanel/ITheme.cs | 28 +- .../Touchpanel/ITswAppControl.cs | 81 +- .../Touchpanel/ITswAppControlMessenger.cs | 2 +- .../Touchpanel/ITswZoomControlMessenger.cs | 2 +- .../MobileControlTouchpanelController.cs | 2 +- .../MobileControlTouchpanelProperties.cs | 57 +- .../Touchpanel/ThemeMessenger.cs | 2 +- .../UserCodeChangedContent.cs | 32 +- .../Volumes.cs | 248 +- .../WebApiHandlers/ActionPathsHandler.cs | 2 +- .../MobileAuthRequestHandler.cs | 2 +- .../WebApiHandlers/MobileInfoHandler.cs | 2 +- .../WebApiHandlers/UiClientHandler.cs | 1 + .../MobileControlWebsocketServer.cs | 64 +- .../WebSocketServer/UiClient.cs | 2 +- .../WebSocketServerSecretProvider.cs | 2 +- ...lsHuddleSpaceFusionSystemControllerBase.cs | 53 +- src/PepperDash.Essentials/HttpLogoServer.cs | 178 +- 522 files changed, 39628 insertions(+), 45678 deletions(-) delete mode 100644 src/PepperDash.Core/ComTextHelper.cs delete mode 100644 src/PepperDash.Core/Comm/eStreamDebuggingSetting.cs create mode 100644 src/PepperDash.Essentials.Core/Devices/eSourceListItemDestinationTypes.cs diff --git a/src/PepperDash.Core/ComTextHelper.cs b/src/PepperDash.Core/ComTextHelper.cs deleted file mode 100644 index 28a76975..00000000 --- a/src/PepperDash.Core/ComTextHelper.cs +++ /dev/null @@ -1,43 +0,0 @@ -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)); - } - } -} \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/CommunicationGather.cs b/src/PepperDash.Core/Comm/CommunicationGather.cs index e75a012d..4131d364 100644 --- a/src/PepperDash.Core/Comm/CommunicationGather.cs +++ b/src/PepperDash.Core/Comm/CommunicationGather.cs @@ -8,8 +8,8 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Core -{ +namespace PepperDash.Core; + /// /// Defines the string event handler for line events on the gather /// @@ -30,7 +30,7 @@ namespace PepperDash.Core /// /// The communication port that this gathers on /// - public ICommunicationReceiver Port { get; private set; } + public ICommunicationReceiver Port { get; private set; } /// /// Default false. If true, the delimiter will be included in the line output @@ -67,22 +67,22 @@ namespace PepperDash.Core /// /// /// - public CommunicationGather(ICommunicationReceiver port, string delimiter) - :this(port, new 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; - } + /// + /// Constructor for using an array of string delimiters + /// + /// + /// + public CommunicationGather(ICommunicationReceiver port, string[] delimiters) + { + Port = port; + StringDelimiters = delimiters; + port.TextReceived += Port_TextReceivedStringDelimiter; + } /// /// Stop method @@ -135,35 +135,35 @@ namespace PepperDash.Core ReceiveBuffer.Append(args.Text); var str = ReceiveBuffer.ToString(); - // Case: Receiving DEVICE get version\x0d\0x0a+OK "value":"1234"\x0d\x0a + // 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" + // 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) + // 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++) { - 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]); + 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]); + } } } @@ -174,5 +174,4 @@ namespace PepperDash.Core { Stop(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs b/src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs index 780e65d0..4739912a 100644 --- a/src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs +++ b/src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs @@ -1,138 +1,157 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; -namespace 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 { /// - /// Controls the ability to disable/enable debugging of TX/RX data sent to/from a device with a built in timer to disable + /// Device Key that this instance configures /// - public class CommunicationStreamDebugging + public string ParentDeviceKey { get; private set; } + + /// + /// Timer to disable automatically if not manually disabled + /// + private CTimer DebugExpiryPeriod; + + /// + /// The current debug setting + /// + public eStreamDebuggingSetting DebugSetting { get; private set; } + + private uint _DebugTimeoutInMs; + private const uint _DefaultDebugTimeoutMin = 30; + + /// + /// Timeout in Minutes + /// + public uint DebugTimeoutMinutes { - /// - /// 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 { - 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; + return _DebugTimeoutInMs/60000; } } + + /// + /// Indicates that receive stream debugging is enabled + /// + 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 + /// + /// + public void SetDebuggingWithDefaultTimeout(eStreamDebuggingSetting setting) + { + if (setting == eStreamDebuggingSetting.Off) + { + DisableDebugging(); + return; + } + + SetDebuggingWithSpecificTimeout(setting, _DefaultDebugTimeoutMin); + } + + /// + /// Sets the debugging setting for the specified number of minutes + /// + /// + /// + 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; + } } + +/// +/// 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 +} + diff --git a/src/PepperDash.Core/Comm/ControlPropertiesConfig.cs b/src/PepperDash.Core/Comm/ControlPropertiesConfig.cs index a7d2300a..e359eade 100644 --- a/src/PepperDash.Core/Comm/ControlPropertiesConfig.cs +++ b/src/PepperDash.Core/Comm/ControlPropertiesConfig.cs @@ -8,91 +8,90 @@ using JsonProperty = NewtonsoftJson::Newtonsoft.Json.JsonPropertyAttribute; using NullValueHandling = NewtonsoftJson::Newtonsoft.Json.NullValueHandling; using StringEnumConverter = NewtonsoftJson::Newtonsoft.Json.Converters.StringEnumConverter; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Config properties that indicate how to communicate with a device for control +/// +public class ControlPropertiesConfig { /// - /// Represents a ControlPropertiesConfig + /// The method of control /// - public class ControlPropertiesConfig - { - /// - /// The method of control - /// - [JsonProperty("method")] - [JsonConverter(typeof(StringEnumConverter))] - public eControlMethod Method { get; set; } + [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 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 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; } + /// + /// 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; } + /// + /// 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 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; } + /// + /// 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); } } + /// + /// 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; } + /// + /// 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; } + /// + /// 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; } + /// + /// 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; } + /// + /// Used when communcating to programs running in VC-4 + /// + [JsonProperty("roomId", NullValueHandling = NullValueHandling.Ignore)] + public string RoomId { get; set; } - /// - /// Constructor - /// - public ControlPropertiesConfig() - { - } + /// + /// Constructor + /// + public ControlPropertiesConfig() + { } } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/EventArgs.cs b/src/PepperDash.Core/Comm/EventArgs.cs index 0b394423..d68dda7c 100644 --- a/src/PepperDash.Core/Comm/EventArgs.cs +++ b/src/PepperDash.Core/Comm/EventArgs.cs @@ -16,236 +16,237 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; -namespace PepperDash.Core +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 { /// - /// Delegate for notifying of socket status changes + /// Gets or sets the Client + /// + public ISocketStatus Client { get; private set; } + + /// + /// Constructor /// /// - 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() { } + 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; } /// - /// Delegate for notifying of TCP Server state changes + /// Constructor /// /// - public delegate void GenericTcpServerStateChangedEventDelegate(ServerState state); + 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 +{ + /// + /// Gets or sets the Socket + /// + public object Socket { get; private set; } /// - /// EventArgs class for TCP Server state changes + /// Gets or sets the index of the client from which the status change was received /// - public class GenericTcpServerStateChangedEventArgs : EventArgs - { - /// - /// Gets or sets the State - /// - public ServerState State { get; private set; } + public uint ReceivedFromClientIndex { get; private set; } - /// - /// - /// - /// - public GenericTcpServerStateChangedEventArgs(ServerState state) - { - State = state; - } - /// - /// S+ Constructor - /// - public GenericTcpServerStateChangedEventArgs() { } + /// + /// Gets or sets the ClientStatus + /// + public SocketStatus ClientStatus { get; set; } + + /// + /// Constructor + /// + /// + /// + public GenericTcpServerSocketStatusChangeEventArgs(object socket, SocketStatus clientStatus) + { + Socket = socket; + ClientStatus = clientStatus; } /// - /// Delegate for TCP Server socket status changes + /// Constructor /// /// /// /// - public delegate void GenericTcpServerSocketStatusChangeEventDelegate(object socket, uint clientIndex, SocketStatus clientStatus); - /// - /// EventArgs for TCP server socket status changes - /// - public class GenericTcpServerSocketStatusChangeEventArgs : EventArgs + public GenericTcpServerSocketStatusChangeEventArgs(object socket, uint clientIndex, SocketStatus clientStatus) { - /// - /// - /// - public object Socket { get; private set; } - /// - /// - /// - public uint ReceivedFromClientIndex { get; private set; } - /// - /// - /// - public SocketStatus ClientStatus { get; set; } + Socket = socket; + ReceivedFromClientIndex = clientIndex; + ClientStatus = clientStatus; + } + /// + /// S+ Constructor + /// + public GenericTcpServerSocketStatusChangeEventArgs() { } +} - /// - /// - /// - /// - /// - public GenericTcpServerSocketStatusChangeEventArgs(object socket, SocketStatus clientStatus) - { - Socket = socket; - ClientStatus = clientStatus; - } +/// +/// EventArgs for TCP server com method receive text +/// +public class GenericTcpServerCommMethodReceiveTextArgs : EventArgs +{ + /// + /// Gets or sets the index of the client from which the text was received + /// + public uint ReceivedFromClientIndex { get; private set; } - /// - /// - /// - /// - /// - /// - public GenericTcpServerSocketStatusChangeEventArgs(object socket, uint clientIndex, SocketStatus clientStatus) + /// + /// Gets the index of the client from which the text was received as a ushort + /// + public ushort ReceivedFromClientIndexShort + { + get { - Socket = socket; - ReceivedFromClientIndex = clientIndex; - ClientStatus = clientStatus; + return (ushort)ReceivedFromClientIndex; } - /// - /// S+ Constructor - /// - public GenericTcpServerSocketStatusChangeEventArgs() { } } /// - /// EventArgs for TCP server com method receive text + /// Gets or sets the Text /// - public class GenericTcpServerCommMethodReceiveTextArgs : EventArgs + public string Text { get; private set; } + + /// + /// Constructor + /// + /// + public GenericTcpServerCommMethodReceiveTextArgs(string text) { - /// - /// - /// - 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() { } + Text = text; } /// - /// EventArgs for TCP server client ready for communication + /// Constructor /// - public class GenericTcpServerClientReadyForcommunicationsEventArgs : EventArgs + /// + /// + public GenericTcpServerCommMethodReceiveTextArgs(string text, uint clientIndex) { - /// - /// - /// - public bool IsReady; + Text = text; + ReceivedFromClientIndex = clientIndex; + } + /// + /// S+ Constructor + /// + public GenericTcpServerCommMethodReceiveTextArgs() { } +} - /// - /// - /// - /// - public GenericTcpServerClientReadyForcommunicationsEventArgs(bool isReady) - { - IsReady = isReady; - } - /// - /// S+ Constructor - /// - public GenericTcpServerClientReadyForcommunicationsEventArgs() { } +/// +/// EventArgs for TCP server client ready for communication +/// +public class GenericTcpServerClientReadyForcommunicationsEventArgs : EventArgs +{ + /// + /// Gets or sets IsReady + /// + public bool IsReady; + + /// + /// Constructor + /// + /// + public GenericTcpServerClientReadyForcommunicationsEventArgs(bool isReady) + { + IsReady = isReady; } /// - /// EventArgs for UDP connected + /// S+ Constructor /// - public class GenericUdpConnectedEventArgs : EventArgs + public GenericTcpServerClientReadyForcommunicationsEventArgs() { } +} + +/// +/// EventArgs for UDP connected +/// +public class GenericUdpConnectedEventArgs : EventArgs +{ + /// + /// Gets or sets the UConnected + /// + public ushort UConnected; + + /// + /// Gets or sets the Connected status + /// + public bool Connected; + + /// + /// Constructor + /// + public GenericUdpConnectedEventArgs() { } + + /// + /// Constructor + /// + /// + public GenericUdpConnectedEventArgs(ushort uconnected) { - /// - /// - /// - public ushort UConnected; - /// - /// - /// - public bool Connected; - - /// - /// Constructor - /// - public GenericUdpConnectedEventArgs() { } - - /// - /// - /// - /// - public GenericUdpConnectedEventArgs(ushort uconnected) - { - UConnected = uconnected; - } - - /// - /// - /// - /// - public GenericUdpConnectedEventArgs(bool connected) - { - Connected = connected; - } - + UConnected = uconnected; } - + /// + /// Constructor + /// + /// + public GenericUdpConnectedEventArgs(bool connected) + { + Connected = connected; + } + +} -} \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/GenericSecureTcpIpClient.cs b/src/PepperDash.Core/Comm/GenericSecureTcpIpClient.cs index 204c548b..36e405b0 100644 --- a/src/PepperDash.Core/Comm/GenericSecureTcpIpClient.cs +++ b/src/PepperDash.Core/Comm/GenericSecureTcpIpClient.cs @@ -7,952 +7,947 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; -namespace PepperDash.Core +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"; /// - /// A class to handle secure TCP/IP communications with a server + /// Stream debugging /// - public class GenericSecureTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect + 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 { - 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() + get { return _hostname; } + set { + _hostname = value; 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(); + _client.AddressClientConnectedTo = _hostname; } } + } - /// - /// Disconnect method - /// - public void Disconnect() + /// + /// Port on server + /// + 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 { - this.LogVerbose("Disconnect Called"); + return _client == null ? SocketStatus.SOCKET_STATUS_NO_CONNECT : _client.ClientStatus; + } + } - DisconnectCalledByUser = true; + /// + /// 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; } + } - // stop trying reconnects, if we are + /// + /// 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(); } } + + /// + /// 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; + + /// + /// + /// + public bool Connected + { + get { return _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } + } + + // private Timer for auto reconnect + private CTimer RetryTimer; + + #endregion + + #region GenericSecureTcpIpClient properties + + /// + /// 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; + } + } + + /// + /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module + /// + 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; + + /// + /// 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); } + } + + /// + /// 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; + } + + /// + /// Just to help S+ set the key + /// + 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) + { + this.LogWarning( "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) + { + this.LogError("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) + { + this.LogInformation("Program stopping. Closing _client connection"); + ProgramIsStopping = true; + Disconnect(); + } + + } + + /// + /// Deactivate the client + /// + /// + public override bool Deactivate() + { + if (_client != null) + { + _client.SocketStatusChange -= this.Client_SocketStatusChange; + DisconnectClient(); + } + return true; + } + + /// + /// Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name. + /// + public void Connect() + { + ConnectionCount++; + this.LogVerbose("Attempting connect Count:{0}", ConnectionCount); + + + if (IsConnected) + { + this.LogInformation("Already connected. Ignoring."); + return; + } + if (IsTryingToConnect) + { + this.LogInformation("Already trying to connect. Ignoring."); + return; + } + try + { + IsTryingToConnect = true; if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } - - if (_client != null) + if (string.IsNullOrEmpty(Hostname)) { - DisconnectClient(); - this.LogDebug("Disconnected"); + this.LogWarning("DynamicTcpClient: No address set"); + return; + } + if (Port < 1 || Port > 65535) + { + this.LogWarning("DynamicTcpClient: Invalid port"); + return; + } + if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) + { + this.LogWarning("DynamicTcpClient: No Shared Key set"); + return; } - } - /// - /// 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() - { + // clean up previous client if (_client != null) { - Debug.Console(2, this, "Cleaning up remotely closed/failed connection."); Disconnect(); } - if (!DisconnectCalledByUser && AutoReconnect) + 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 => { - 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) + this.LogError("Connect attempt has not finished after 30sec Count:{0}", ConnectionCount); + if (IsTryingToConnect) { - RetryTimer.Stop(); - RetryTimer = null; + IsTryingToConnect = false; + + //if (ConnectionHasHungCallback != null) + //{ + // ConnectionHasHungCallback(); + //} + //SecureClient.DisconnectFromServer(); + //CheckClosedAndTryReconnect(); } - if (AutoReconnectTriggered != null) - AutoReconnectTriggered(this, new EventArgs()); - RetryTimer = new CTimer(o => Connect(), rndTime); - } - } + }, 30000); - /// - /// Receive callback - /// - /// - /// - void Receive(SecureTCPClient client, int numBytes) - { - if (numBytes > 0) + this.LogVerbose("Making Connection Count:{0}", ConnectionCount); + _client.ConnectToServerAsync(o => { - string str = string.Empty; - var handler = TextReceivedQueueInvoke; - try + this.LogVerbose("ConnectToServerAsync Count:{0} Ran!", ConnectionCount); + + if (ConnectFailTimer != null) { - 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))) + ConnectFailTimer.Stop(); + } + IsTryingToConnect = false; + + if (o.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + { + this.LogVerbose("_client connected to {0} on port {1}", o.AddressClientConnectedTo, o.LocalPortNumberOfClient); + o.ReceiveDataAsync(Receive); + + if (SharedKeyRequired) { - - if (SharedKeyRequired && str == "SharedKey:") + WaitingForSharedKeyResponse = true; + WaitForSharedKey = new CTimer(timer => { - 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 + this.LogWarning("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) { - //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)); - } + OnClientReadyForcommunications(true); // Key not required } } } - catch (Exception ex) + else { - Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); + this.LogWarning("Connect attempt failed {0}", o.ClientStatus); + CheckClosedAndTryReconnect(); } - if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - client.ReceiveDataAsync(Receive); + }); + } + catch (Exception ex) + { + this.LogError("_client connection exception: {0}", ex.Message); + IsTryingToConnect = false; + CheckClosedAndTryReconnect(); + } + } - //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(); - } + /// + /// + /// + public void Disconnect() + { + this.LogVerbose("Disconnect Called"); + + DisconnectCalledByUser = true; + + // stop trying reconnects, if we are + if (RetryTimer != null) + { + RetryTimer.Stop(); + RetryTimer = null; } - /// - /// 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() + if (_client != null) { + DisconnectClient(); + this.LogDebug("Disconnected"); + } + } + + /// + /// Does the actual disconnect business + /// + public void DisconnectClient() + { + if (_client == null) return; + + this.LogInformation("Disconnecting client"); + if (IsConnected) + _client.DisconnectFromServer(); + + // close up client. ALWAYS use this when disconnecting. + IsTryingToConnect = false; + + this.LogVerbose("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) + { + this.LogVerbose("Cleaning up remotely closed/failed connection."); + Disconnect(); + } + if (!DisconnectCalledByUser && AutoReconnect) + { + var halfInterval = AutoReconnectIntervalMs / 2; + var rndTime = new Random().Next(-halfInterval, halfInterval) + AutoReconnectIntervalMs; + this.LogVerbose("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 { - while (true) + var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); + str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + this.LogVerbose("_client Received:\r--------\r{0}\r--------", str); + if (!string.IsNullOrEmpty(checkHeartbeat(str))) { - // 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) + + if (SharedKeyRequired && str == "SharedKey:") { - handler(this, message); + this.LogVerbose("Server asking for shared key, sending"); + SendText(SharedKey + "\n"); + } + else if (SharedKeyRequired && str == "Shared Key Match") + { + StopWaitForSharedKeyTimer(); + + + this.LogVerbose("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 e) + catch (Exception ex) { - this.LogException(e, "DequeueEvent error"); + this.LogError("Error receiving data: {1}. Error: {0}", str, ex.Message); } - // 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) + 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) { - DequeueLock.Leave(); + 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.LogError(e, "DequeueEvent error: {0}", e.Message); + } + // 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 HeartbeatStart() + } + void HeartbeatStop() + { + + if (HeartbeatSendTimer != null) + { + this.LogVerbose("Stoping Heartbeat Send"); + HeartbeatSendTimer.Stop(); + HeartbeatSendTimer = null; + } + if (HeartbeatAckTimer != null) + { + this.LogVerbose("Stoping Heartbeat Ack"); + HeartbeatAckTimer.Stop(); + HeartbeatAckTimer = null; + } + + } + void SendHeartbeat(object notused) + { + this.SendText(HeartbeatString); + this.LogVerbose("Sending Heartbeat"); + + } + + //private method to check heartbeat requirements and start or reset timer + string checkHeartbeat(string received) + { + try { if (HeartbeatEnabled) { - this.LogVerbose("Starting Heartbeat"); - if (HeartbeatSendTimer == null) + if (!string.IsNullOrEmpty(HeartbeatString)) { - - 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)) { - var remainingText = received.Replace(HeartbeatString, ""); - var noDelimiter = received.Trim(new char[] { '\r', '\n' }); - if (noDelimiter.Contains(HeartbeatString)) + if (HeartbeatAckTimer != null) { - 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; + HeartbeatAckTimer.Reset(HeartbeatInterval * 2); } - } - } - } - 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) => + else { - // 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); - } - }); + HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); + } + this.LogVerbose("Heartbeat Received: {0}, from Server", HeartbeatString); + return remainingText; } } - catch (Exception ex) - { - Debug.Console(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); - } } } - - /// - /// SendBytes method - /// - public void SendBytes(byte[] bytes) + catch (Exception ex) { - 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); - } - } + this.LogError(ex, "Error checking heartbeat: {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 + return received; } + + + void HeartbeatAckTimerFail(object o) + { + try + { + + if (IsConnected) + { + this.LogWarning("Heartbeat not received from Server...DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE"); + SendText("Heartbeat not received by server, closing connection"); + CheckClosedAndTryReconnect(); + } + + } + catch (Exception ex) + { + this.LogError(ex, "Heartbeat timeout Error on _client: {0}, {1}", Key, ex.Message); + } + } + + /// + /// + /// + void StopWaitForSharedKeyTimer() + { + if (WaitForSharedKey != null) + { + WaitForSharedKey.Stop(); + WaitForSharedKey = null; + } + } + + /// + /// General send 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) + { + this.LogWarning("[{0}] Sent zero bytes. Was there an error?", this.Key); + } + }); + } + } + catch (Exception ex) + { + this.LogError(ex, "Error sending text: {1}. Error: {0}", ex.Message, text); + } + } + } + + /// + /// + /// + 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) + { + this.LogError(ex, "Error sending bytes. Error: {0}", ex.Message); + } + } + } + + /// + /// SocketStatusChange Callback + /// + /// + /// + void Client_SocketStatusChange(SecureTCPClient client, SocketStatus clientSocketStatus) + { + if (ProgramIsStopping) + { + ProgramIsStopping = false; + return; + } + try + { + this.LogVerbose("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) + { + this.LogError(ex, "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 } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/GenericSecureTcpIpClient_ForServer.cs b/src/PepperDash.Core/Comm/GenericSecureTcpIpClient_ForServer.cs index 49350164..d46ce374 100644 --- a/src/PepperDash.Core/Comm/GenericSecureTcpIpClient_ForServer.cs +++ b/src/PepperDash.Core/Comm/GenericSecureTcpIpClient_ForServer.cs @@ -19,891 +19,890 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Generic secure TCP/IP client for server +/// +public class GenericSecureTcpIpClient_ForServer : Device, IAutoReconnect { /// - /// Generic secure TCP/IP client for server + /// Band aid delegate for choked server /// - public class GenericSecureTcpIpClient_ForServer : Device, IAutoReconnect + 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; } + + /// + /// The port number on which the server is listening. + /// + public int Port { get; set; } + + /// + /// S+ helper + /// + public ushort UPort { - /// - /// Band aid delegate for choked server - /// - internal delegate void ConnectionHasHungCallbackDelegate(); + get { return Convert.ToUInt16(Port); } + set { Port = Convert.ToInt32(value); } + } - #region Events + /// + /// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class + /// + public bool SharedKeyRequired { get; set; } - //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 + /// + /// S+ helper for requires shared key bool + /// + public ushort USharedKeyRequired + { + set { - get { return Convert.ToUInt16(Port); } - set { Port = Convert.ToInt32(value); } + if (value == 1) + SharedKeyRequired = true; + else + SharedKeyRequired = false; } + } - /// - /// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class - /// - public bool SharedKeyRequired { get; set; } + /// + /// SharedKey is sent for verification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module + /// + public string SharedKey { get; set; } - /// - /// S+ helper for requires shared key bool - /// - public ushort USharedKeyRequired + /// + /// flag to show the client is waiting for the server to send the shared key + /// + private bool WaitingForSharedKeyResponse { get; set; } + + /// + /// Defaults to 2000 + /// + public int BufferSize { get; set; } + + /// + /// Semaphore on connect method + /// + bool IsTryingToConnect; + + /// + /// Bool showing if socket is connected + /// + public bool IsConnected + { + get { - set + 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 + + /// + /// Initializes the client's key property, which is used to identify this client instance. + /// + /// The unique key that identifies this client instance. + 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. + /// + /// The configuration object containing the client's settings. + public void Initialize(TcpClientConfigObject clientConfigObject) + { + try + { + if (clientConfigObject != null) { - if (value == 1) - SharedKeyRequired = true; - else - SharedKeyRequired = false; + 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); } - } - - /// - /// 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 + else { ErrorLog.Error("Could not initialize client with key: {0}", Key); } } - - /// - /// Handles closing this up when the program shuts down - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + catch { - if (programEventType == eProgramStatusEventType.Stopping || programEventType == eProgramStatusEventType.Paused) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing Client connection"); - ProgramIsStopping = true; - Disconnect(); - } + 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) + { + this.LogInformation("Program stopping. Closing Client connection"); + ProgramIsStopping = true; + Disconnect(); } - /// - /// Connect method - /// - public void Connect() + } + + /// + /// Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name. + /// + public void Connect() + { + ConnectionCount++; + this.LogVerbose("Attempting connect Count:{0}", ConnectionCount); + + + if (IsConnected) { - 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(); - } + this.LogInformation("Already connected. Ignoring."); + return; } - - /// - /// Disconnect method - /// - public void Disconnect() + if (IsTryingToConnect) { - this.LogVerbose("Disconnect Called"); - - DisconnectCalledByUser = true; - if (IsConnected) - { - Client.DisconnectFromServer(); - - } + this.LogInformation("Already trying to connect. Ignoring."); + return; + } + try + { + IsTryingToConnect = true; if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } - Cleanup(); - } - - /// - /// Internal call to close up client. ALWAYS use this when disconnecting. - /// - void Cleanup() - { - IsTryingToConnect = false; + if (string.IsNullOrEmpty(Hostname)) + { + this.LogWarning("DynamicTcpClient: No address set"); + return; + } + if (Port < 1 || Port > 65535) + { + this.LogWarning("DynamicTcpClient: Invalid port"); + return; + } + if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) + { + this.LogWarning("DynamicTcpClient: No Shared Key set"); + return; + } + // clean up previous client 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) + 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 => { - 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) + this.LogError("Connect attempt has not finished after 30sec Count:{0}", ConnectionCount); + if (IsTryingToConnect) { - RetryTimer.Stop(); - RetryTimer = null; + IsTryingToConnect = false; + + //if (ConnectionHasHungCallback != null) + //{ + // ConnectionHasHungCallback(); + //} + //SecureClient.DisconnectFromServer(); + //CheckClosedAndTryReconnect(); } - if(AutoReconnectTriggered != null) - AutoReconnectTriggered(this, new EventArgs()); - RetryTimer = new CTimer(o => Connect(), rndTime); - } - } + }, 30000); - /// - /// Receive callback - /// - /// - /// - void Receive(SecureTCPClient client, int numBytes) - { - if (numBytes > 0) + this.LogVerbose("Making Connection Count:{0}", ConnectionCount); + Client.ConnectToServerAsync(o => { - string str = string.Empty; - var handler = TextReceivedQueueInvoke; - try + this.LogVerbose("ConnectToServerAsync Count:{0} Ran!", ConnectionCount); + + if (ConnectFailTimer != null) { - 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))) + ConnectFailTimer.Stop(); + } + IsTryingToConnect = false; + + if (o.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + { + this.LogVerbose("Client connected to {0} on port {1}", o.AddressClientConnectedTo, o.LocalPortNumberOfClient); + o.ReceiveDataAsync(Receive); + + if (SharedKeyRequired) { - - if (SharedKeyRequired && str == "SharedKey:") + WaitingForSharedKeyResponse = true; + WaitForSharedKey = new CTimer(timer => { - 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 + this.LogWarning("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) { - //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)); - } + OnClientReadyForcommunications(true); // Key not required } } } - catch (Exception ex) + else { - Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); + this.LogWarning("Connect attempt failed {0}", o.ClientStatus); + CheckClosedAndTryReconnect(); } - 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() + catch (Exception ex) { + this.LogError("Client connection exception: {0}", ex.Message); + IsTryingToConnect = false; + CheckClosedAndTryReconnect(); + } + } + + /// + /// + /// + 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(); + this.LogVerbose("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) + { + this.LogVerbose("Cleaning up remotely closed/failed connection."); + Cleanup(); + } + if (!DisconnectCalledByUser && AutoReconnect) + { + var halfInterval = AutoReconnectIntervalMs / 2; + var rndTime = new Random().Next(-halfInterval, halfInterval) + AutoReconnectIntervalMs; + this.LogVerbose("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 { - while (true) + var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); + str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + this.LogVerbose("Client Received:\r--------\r{0}\r--------", str); + if (!string.IsNullOrEmpty(checkHeartbeat(str))) { - // 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) + + if (SharedKeyRequired && str == "SharedKey:") { - handler(this, message); + this.LogVerbose("Server asking for shared key, sending"); + SendText(SharedKey + "\n"); + } + else if (SharedKeyRequired && str == "Shared Key Match") + { + StopWaitForSharedKeyTimer(); + + + this.LogVerbose("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 e) + catch (Exception ex) { - this.LogException(e, "DequeueEvent error"); + this.LogError("Error receiving data: {1}. Error: {0}", ex.Message, str); } - // 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) + 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) { - DequeueLock.Leave(); + 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.LogError("DequeueEvent error: {0}", e.Message, e); + } + // 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 HeartbeatStart() + } + void HeartbeatStop() + { + + if (HeartbeatSendTimer != null) + { + this.LogVerbose("Stopping Heartbeat Send"); + HeartbeatSendTimer.Stop(); + HeartbeatSendTimer = null; + } + if (HeartbeatAckTimer != null) + { + this.LogVerbose("Stopping Heartbeat Ack"); + HeartbeatAckTimer.Stop(); + HeartbeatAckTimer = null; + } + + } + void SendHeartbeat(object notused) + { + this.SendText(HeartbeatString); + this.LogVerbose("Sending Heartbeat"); + + } + + //private method to check heartbeat requirements and start or reset timer + string checkHeartbeat(string received) + { + try { if (HeartbeatEnabled) { - Debug.Console(2, this, "Starting Heartbeat"); - if (HeartbeatSendTimer == null) + if (!string.IsNullOrEmpty(HeartbeatString)) { - - 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)) { - var remainingText = received.Replace(HeartbeatString, ""); - var noDelimiter = received.Trim(new char[] { '\r', '\n' }); - if (noDelimiter.Contains(HeartbeatString)) + if (HeartbeatAckTimer != null) { - 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; + HeartbeatAckTimer.Reset(HeartbeatInterval * 2); } - } - } - } - 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) => + else { - // 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); - } - }); + HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); + } + this.LogVerbose("Heartbeat Received: {0}, from Server", HeartbeatString); + return remainingText; } } - catch (Exception ex) - { - Debug.Console(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); - } } } - - /// - /// SendBytes method - /// - public void SendBytes(byte[] bytes) + catch (Exception ex) { - 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); - } - } + this.LogError("Error checking heartbeat: {0}", ex.Message, ex); } - - /// - /// 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 + return received; } + + + void HeartbeatAckTimerFail(object o) + { + try + { + + if (IsConnected) + { + this.LogWarning("Heartbeat not received from Server...DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE"); + SendText("Heartbeat not received by server, closing connection"); + CheckClosedAndTryReconnect(); + } + + } + catch (Exception ex) + { + this.LogError("Heartbeat timeout Error on Client: {0}, {1}", Key, ex); + } + } + + /// + /// + /// + void StopWaitForSharedKeyTimer() + { + if (WaitForSharedKey != null) + { + WaitForSharedKey.Stop(); + WaitForSharedKey = null; + } + } + + /// + /// General send 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) + { + this.LogWarning("[{0}] Sent zero bytes. Was there an error?", this.Key); + } + }); + } + } + catch (Exception ex) + { + this.LogError("Error sending text: {1}. Error: {0}", text, ex.Message); + } + } + } + + /// + /// + /// + 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) + { + this.LogError("Error sending bytes. Error: {0}", ex.Message, ex); + } + } + } + + /// + /// SocketStatusChange Callback + /// + /// + /// + void Client_SocketStatusChange(SecureTCPClient client, SocketStatus clientSocketStatus) + { + if (ProgramIsStopping) + { + ProgramIsStopping = false; + return; + } + try + { + this.LogDebug("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) + { + this.LogError("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 } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/GenericSecureTcpIpServer.cs b/src/PepperDash.Core/Comm/GenericSecureTcpIpServer.cs index 6502d544..7fed3948 100644 --- a/src/PepperDash.Core/Comm/GenericSecureTcpIpServer.cs +++ b/src/PepperDash.Core/Comm/GenericSecureTcpIpServer.cs @@ -17,405 +17,403 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Generic secure TCP/IP server +/// +public class GenericSecureTcpIpServer : Device { + #region Events /// - /// Generic secure TCP/IP server + /// Event for Receiving text /// - public class GenericSecureTcpIpServer : Device + 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; } + + /// + /// + /// + 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; + + /// + /// 3 by default + /// + public int MonitorClientMaxFailureCount { get; set; } + + /// + /// Text representation of the Socket Status enum values for the server + /// + public string Status { - #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 { - get - { - if (SecureServer != null) - return SecureServer.State.ToString(); - return ServerState.SERVER_NOT_LISTENING.ToString(); - - } + if (SecureServer != null) + return SecureServer.State.ToString(); + return ServerState.SERVER_NOT_LISTENING.ToString(); } - /// - /// Bool showing if socket is connected - /// - public bool IsConnected + } + + /// + /// Bool showing if socket is connected + /// + public bool IsConnected + { + get { - get - { - if (SecureServer != null) - return (SecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED; + 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_CONNECTED) == ServerState.SERVER_CONNECTED : - // (UnsecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED); - } + //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 UIsConnected + /// + /// 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 { - get { return (ushort)(IsConnected ? 1 : 0); } + if (SecureServer != null) + return (ushort)SecureServer.NumberOfClientsConnected; + return 0; } + } - /// - /// Bool showing if socket is connected - /// - public bool IsListening + /// + /// Port Server should listen on + /// + 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 { - get + if (value == 1) + SharedKeyRequired = true; + else + SharedKeyRequired = false; + } + } + + /// + /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module. + /// If SharedKey changes while server is listening or clients are connected, disconnect and stop listening will be called + /// + 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; + } + } + + /// + /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ + /// + public int HeartbeatRequiredIntervalMs { get; set; } + + /// + /// Simpl+ Heartbeat Analog value in seconds + /// + public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatRequiredIntervalMs = (value * 1000); } } + + /// + /// String to Match for heartbeat. If null or empty any string will reset heartbeat timer + /// + 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(); + + /// + /// Defaults to 2000 + /// + 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 + /// + /// Disconnects all clients and stops the server + /// + 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+ + /// + /// + public void Initialize(string key) + { + Key = key; + } + + /// + /// Initialze the server + /// + /// + public void Initialize(TcpServerConfigObject serverConfigObject) + { + try + { + if (serverConfigObject != null || string.IsNullOrEmpty(serverConfigObject.Key)) { - 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); + 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); } - } - - /// - /// 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 + else { ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); } } - - /// - /// Listen method - /// - public void Listen() + catch { - ServerCCSection.Enter(); - try + ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); + } + } + + /// + /// Start listening on the specified port + /// + public void Listen() + { + ServerCCSection.Enter(); + try + { + if (Port < 1 || Port > 65535) { - 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; - } + 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) @@ -446,19 +444,19 @@ namespace PepperDash.Core 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() + catch (Exception ex) { + ServerCCSection.Leave(); + ErrorLog.Error("{1} Error with Dynamic Server: {0}", ex.ToString(), Key); + } + } + + /// + /// Stop Listeneing + /// + public void StopListening() + { try { Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Stopping Listener"); @@ -474,153 +472,129 @@ namespace PepperDash.Core { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error stopping server. Error: {0}", ex); } - } + } - /// - /// Disconnects Client - /// - /// - /// - /// DisconnectClient method - /// - public void DisconnectClient(uint client) + /// + /// Disconnects Client + /// + /// + public void DisconnectClient(uint client) + { + try { - 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); - } + SecureServer.Disconnect(client); + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", client); } - /// - /// DisconnectAllClientsForShutdown method - /// - public void DisconnectAllClientsForShutdown() + catch (Exception ex) { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Disconnecting All Clients"); - if (SecureServer != null) + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", client, ex); + } + } + /// + /// Disconnect All Clients + /// + 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 { - 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 { - 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); - } + SecureServer.Disconnect(i); + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", i); } - 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) + catch (Exception ex) { - 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); - } - } + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", i, ex); } - CCBroadcast.Leave(); - } - catch (Exception ex) - { - CCBroadcast.Leave(); - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Broadcasting messages from server. Error: {0}", ex.Message); } + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Server Status: {0}", SecureServer.ServerSocketStatus); } - /// - /// Not sure this is useful in library, maybe Pro?? - /// - /// - /// - /// - /// SendTextToClient method - /// - public void SendTextToClient(string text, uint clientIndex) + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected All Clients"); + ConnectedClientsIndexes.Clear(); + + if (!ProgramIsStopping) { - try + OnConnectionChange(); + OnServerStateChange(SecureServer.State); //State shows both listening and connected + } + + // var o = new { }; + } + + /// + /// Broadcast text from server to all connected clients + /// + /// + public void BroadcastText(string text) + { + CCriticalSection CCBroadcast = new CCriticalSection(); + CCBroadcast.Enter(); + try + { + if (ConnectedClientsIndexes.Count > 0) { byte[] b = Encoding.GetEncoding(28591).GetBytes(text); - if (SecureServer != null && SecureServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) + foreach (uint i in ConnectedClientsIndexes) { - if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) - SecureServer.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); + 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); + } } } - catch (Exception ex) + 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?? + /// + /// + /// + 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) { - Debug.Console(2, this, "Error sending text to client. Text: {1}. Error: {0}", ex.Message, text); + if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) + SecureServer.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); } } - - //private method to check heartbeat requirements and start or reset timer - string checkHeartbeat(uint clientIndex, string received) + catch (Exception ex) { - try + 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 (HeartbeatRequired) + if (!string.IsNullOrEmpty(HeartbeatStringToMatch)) { - 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 + 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); @@ -629,182 +603,194 @@ namespace PepperDash.Core 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); + Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", HeartbeatStringToMatch, clientIndex); + // Return Heartbeat + SendTextToClient(HeartbeatStringToMatch, clientIndex); + return remainingText; } } - } - 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 ""; + 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); + } } } - - #endregion - - #region Methods - HeartbeatTimer Callback - - void HeartbeatTimer_CallbackFunction(object o) + catch (Exception ex) { - uint clientIndex = 99999; - string address = string.Empty; - try + Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); + } + return received; + } + + /// + /// Get the IP Address for the client at the specifed index + /// + /// + /// + 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)) { - clientIndex = (uint)o; - address = SecureServer.GetAddressServerAcceptedConnectionFromForSpecificClient(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); + } + } - 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); + #endregion - if (SecureServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) - SendTextToClient("Heartbeat not received by server, closing connection", clientIndex); + #region Methods - Socket Status Changed Callbacks + /// + /// Secure Server Socket Status Changed Callback + /// + /// + /// + /// + void SecureServer_SocketStatusChange(SecureTCPServer server, uint clientIndex, SocketStatus serverSocketStatus) + { + try + { + - var discoResult = SecureServer.Disconnect(clientIndex); - //Debug.Console(1, this, "{0}", discoResult); - - if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) + // 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); } - } - 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 (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) + catch (Exception ex) { - try + 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) { - 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 (server.ClientConnected(clientIndex)) + + if (!ConnectedClientsIndexes.Contains(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); + ConnectedClientsIndexes.Add(clientIndex); } - } - else - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Client attempt faulty."); + 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); } } - catch (Exception ex) + else { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Connect Callback. Error: {0}", ex); + 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); @@ -820,279 +806,278 @@ namespace PepperDash.Core } } - #endregion + #endregion - #region Methods - Send/Receive Callbacks - /// - /// Secure Received Data Async Callback - /// - /// - /// - /// - void SecureReceivedDataAsyncCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesReceived) + #region Methods - Send/Receive Callbacks + /// + /// Secure Received Data Async Callback + /// + /// + /// + /// + void SecureReceivedDataAsyncCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesReceived) + { + if (numberOfBytesReceived > 0) { - if (numberOfBytesReceived > 0) - { - string received = "Nothing"; - var handler = TextReceivedQueueInvoke; - try + 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)) { - 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) { - 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; - } + 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)); - } - } + 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); } - catch (Exception ex) + else if (!string.IsNullOrEmpty(checkHeartbeat(clientIndex, received))) { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Receiving data: {0}. Error: {1}", received, ex); + 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()); - } + //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() + /// + /// 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 { - try + while (true) { - 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; + // 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, new GenericTcpServerSocketStatusChangeEventArgs(SecureServer, clientIndex, clientStatus)); + handler(this, message); } } } - - //Private Helper method to call the Connection Change Event - void OnConnectionChange() + catch (Exception e) + { + this.LogError(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 { - if (ProgramIsStopping) - { - return; - } var handler = ClientConnectionChange; if (handler != null) { - handler(this, new GenericTcpServerSocketStatusChangeEventArgs()); + handler(this, new GenericTcpServerSocketStatusChangeEventArgs(SecureServer, clientIndex, clientStatus)); } } + } - //Private Helper Method to call the Text Received Event - void onTextReceived(string text, uint clientIndex) + //Private Helper method to call the Connection Change Event + void OnConnectionChange() + { + if (ProgramIsStopping) { - var handler = TextReceived; - if (handler != null) - handler(this, new GenericTcpServerCommMethodReceiveTextArgs(text, clientIndex)); + return; } - - //Private Helper Method to call the Server State Change Event - void OnServerStateChange(ServerState state) + var handler = ClientConnectionChange; + if (handler != null) { - if (ProgramIsStopping) - { - return; - } - var handler = ServerStateChange; - if (handler != null) - { - handler(this, new GenericTcpServerStateChangedEventArgs(state)); - } + handler(this, new GenericTcpServerSocketStatusChangeEventArgs()); } + } - /// - /// Private Event Handler method to handle the closing of connections when the program stops - /// - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + //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) { - 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(); - } + return; } - - //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) + var handler = ServerStateChange; + if (handler != null) { - ClientReadyAfterKeyExchange.Add(clientIndex); - var handler = ServerClientReadyForCommunications; - if (handler != null) - handler(this, new GenericTcpServerSocketStatusChangeEventArgs( - this, clientIndex, SecureServer.GetServerSocketStatusForSpecificClient(clientIndex))); + handler(this, new GenericTcpServerStateChangedEventArgs(state)); } - #endregion + } - #region Monitor Client - /// - /// Starts the monitor client cycle. Timed wait, then call RunMonitorClient - /// - void StartMonitorClient() + /// + /// 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) - { - 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 (MonitorClient != null) + MonitorClient.Disconnect(); - /// - /// If the client hangs, add to counter and maybe fire the choke event - /// - void MonitorClientHasHungCallback() + 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) { - MonitorClientFailureCount++; + 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(); - 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 - } + StartMonitorClient(); } - #endregion } + + /// + /// 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 } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/GenericSshClient.cs b/src/PepperDash.Core/Comm/GenericSshClient.cs index df44ab51..edc89a84 100644 --- a/src/PepperDash.Core/Comm/GenericSshClient.cs +++ b/src/PepperDash.Core/Comm/GenericSshClient.cs @@ -9,658 +9,562 @@ using PepperDash.Core.Logging; using Renci.SshNet; using Renci.SshNet.Common; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// +/// +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; + + ///// + ///// + ///// + //public event GenericSocketStatusChangeEventDelegate SocketStatusChange; + + /// + /// Address of server + /// + public string Hostname { get; set; } + + /// + /// Port on server + /// + public int Port { get; set; } + + /// + /// Username for server + /// + public string Username { get; set; } + + /// + /// And... Password for server. That was worth documenting! + /// + 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); } + } + /// /// SSH Client /// - public class GenericSshClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect + public SocketStatus ClientStatus { - 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 + get { return _ClientStatus; } + private set { - // returns false if no client or not connected - get { return client != null && ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } + if (_ClientStatus == value) + return; + _ClientStatus = value; + OnConnectionChange(); } + } + SocketStatus _ClientStatus; - /// - /// S+ helper for IsConnected - /// - public ushort UIsConnected - { - get { return (ushort)(IsConnected ? 1 : 0); } - } + /// + /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event + /// and IsConnected with be true when this == 2. + /// + public ushort UStatus + { + get { return (ushort)_ClientStatus; } + } - /// - /// Socket status change event - /// - public SocketStatus ClientStatus - { - get { lock (_stateLock) { return _ClientStatus; } } - private set - { - bool shouldFireEvent = false; - lock (_stateLock) + /// + /// 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; private set; } + + /// + /// S+ helper for AutoReconnect + /// + public ushort UAutoReconnect + { + get { return (ushort)(AutoReconnect ? 1 : 0); } + set { AutoReconnect = value == 1; } + } + + /// + /// Millisecond value, determines the timeout period in between reconnect attempts. + /// Set to 5000 by default + /// + public int AutoReconnectIntervalMs { get; set; } + + SshClient Client; + + ShellStream TheStream; + + CTimer ReconnectTimer; + + //Lock object to prevent simulatneous connect/disconnect operations + //private CCriticalSection connectLock = new CCriticalSection(); + private SemaphoreSlim connectLock = new SemaphoreSlim(1); + + private bool DisconnectLogged = false; + + /// + /// 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 CTimer(o => { - 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 + if (ConnectEnabled) { Connect(); } - }, null, System.Threading.Timeout.Infinite, 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 CTimer(o => + { + if (ConnectEnabled) + { + Connect(); + } + }, System.Threading.Timeout.Infinite); + } + + /// + /// Handles closing this up when the program shuts down + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping) + { + if (Client != null) + { + this.LogDebug("Program stopping. Closing connection"); + Disconnect(); + } + } + } + + /// + /// Connect to the server, using the provided properties. + /// + 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; } - /// - /// S+ Constructor - Must set all properties before calling Connect - /// - public GenericSshClient() - : base(SPlusKey) - { - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - AutoReconnectIntervalMs = 5000; + ConnectEnabled = true; - reconnectTimer = new Timer(o => + try + { + connectLock.Wait(); + if (IsConnected) { - if (ConnectEnabled) // Now thread-safe property access + this.LogDebug("Connection already connected. Exiting Connect"); + } + else + { + this.LogDebug("Attempting connect"); + + // Cancel reconnect if running. + if (ReconnectTimer != null) { - Connect(); + ReconnectTimer.Stop(); } - }, 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) + // Cleanup the old client if it already exists + if (Client != null) { - this.LogDebug("Program stopping. Closing connection"); - Disconnect(); + 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(); + TheStream = Client.CreateShellStream("PDTShell", 0, 0, 0, 0, 65534); + if (TheStream.DataAvailable) + { + // empty the buffer if there is data + string str = TheStream.Read(); + } + TheStream.DataReceived += Stream_DataReceived; + this.LogInformation("Connected"); + ClientStatus = SocketStatus.SOCKET_STATUS_CONNECTED; + DisconnectLogged = false; + } + catch (SshConnectionException e) + { + var ie = e.InnerException; // The details are inside!! + var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error; + + if (ie is SocketException) + { + this.LogException(ie, "CONNECTION failure: Cannot reach host"); + } + + if (ie is System.Net.Sockets.SocketException socketException) + { + this.LogException(ie, "Connection failure: Cannot reach {host} on {port}", + Hostname, Port); + } + if (ie is SshAuthenticationException) + { + this.LogException(ie, "Authentication failure for username {userName}", Username); + } + else + this.LogException(ie, "Error on connect"); + + DisconnectLogged = true; + KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); + if (AutoReconnect) + { + this.LogDebug("Checking autoreconnect: {autoReconnect}, {autoReconnectInterval}ms", AutoReconnect, AutoReconnectIntervalMs); + ReconnectTimer.Reset(AutoReconnectIntervalMs); + } + } + 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); + ReconnectTimer.Reset(AutoReconnectIntervalMs); + } + } + catch (Exception e) + { + var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error; + this.LogException(e, "Unhandled exception on connect"); + DisconnectLogged = true; + KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); + if (AutoReconnect) + { + this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); + ReconnectTimer.Reset(AutoReconnectIntervalMs); + } } } } - - /// - /// Connect method - /// - public void Connect() + finally { - // Don't go unless everything is here - if (string.IsNullOrEmpty(Hostname) || Port < 1 || Port > 65535 - || Username == null || Password == null) + connectLock.Release(); + } + } + + /// + /// Disconnect method + /// + public void Disconnect() + { + ConnectEnabled = false; + // Stop trying reconnects, if we are + ReconnectTimer.Stop(); + + 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) { - this.LogError("Connect failed. Check hostname, port, username and password are set or not null"); - return; + 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"); + } + } - ConnectEnabled = true; + /// + /// Kills the stream + /// + void KillStream() + { + try + { + if (TheStream != null) + { + TheStream.DataReceived -= Stream_DataReceived; + TheStream.Close(); + TheStream.Dispose(); + TheStream = 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. + /// + 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. + /// + 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); + if (StreamDebugging.RxStreamDebuggingIsEnabled) + { + this.LogInformation("Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); + } + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + } + + var textHandler = TextReceived; + if (textHandler != null) + { + if (StreamDebugging.RxStreamDebuggingIsEnabled) + this.LogInformation("Received: '{0}'", ComTextHelper.GetDebugText(response)); + + textHandler(this, new GenericCommMethodReceiveTextArgs(response)); + } + + } + + + /// + /// Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange + /// event + /// + 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(); - 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(); - } - } - } + KillClient(SocketStatus.SOCKET_STATUS_BROKEN_REMOTELY); } 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 (AutoReconnect && ConnectEnabled) { - if (client != null) - { - client.ErrorOccurred -= Client_ErrorOccurred; - client.Disconnect(); - client.Dispose(); - client = null; - ClientStatus = status; - this.LogDebug("Disconnected"); - } + this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); + ReconnectTimer.Reset(AutoReconnectIntervalMs); } - 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; - } - } - + }); } + /// + /// Helper for ConnectionChange event + /// + void OnConnectionChange() + { + if (ConnectionChange != null) + ConnectionChange(this, new GenericSocketStatusChageEventArgs(this)); + } + + #region IBasicCommunication Members + + /// + /// Sends text to the server + /// + /// + public void SendText(string text) + { + try + { + if (Client != null && TheStream != null && IsConnected) + { + if (StreamDebugging.TxStreamDebuggingIsEnabled) + this.LogInformation( + "Sending {length} characters of text: '{text}'", + text.Length, + ComTextHelper.GetDebugText(text)); + + TheStream.Write(text); + TheStream.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); + ReconnectTimer.Reset(); + } + catch (Exception ex) + { + this.LogException(ex, "Exception sending text: '{message}'", text); + } + } + + /// + /// Sends Bytes to the server + /// + /// + public void SendBytes(byte[] bytes) + { + try + { + if (Client != null && TheStream != null && IsConnected) + { + if (StreamDebugging.TxStreamDebuggingIsEnabled) + this.LogInformation("Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + + TheStream.Write(bytes, 0, bytes.Length); + TheStream.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); + ReconnectTimer.Reset(); + } + catch (Exception ex) + { + this.LogException(ex, "Exception sending {message}", ComTextHelper.GetEscapedText(bytes)); + } + } + #endregion + //***************************************************************************************************** //***************************************************************************************************** /// - /// Represents a SshConnectionChangeEventArgs + /// Fired when connection changes /// public class SshConnectionChangeEventArgs : EventArgs { /// /// Connection State /// - public bool IsConnected { get; private set; } + public bool IsConnected { get; private set; } /// - /// Gets or sets the UIsConnected + /// Connection Status represented as a ushort /// public ushort UIsConnected { get { return (ushort)(Client.IsConnected ? 1 : 0); } } /// - /// Gets or sets the Client + /// The client /// public GenericSshClient Client { get; private set; } /// - /// Gets or sets the Status + /// Socket Status as represented by /// public ushort Status { get { return Client.UStatus; } } @@ -674,7 +578,7 @@ namespace PepperDash.Core /// /// Connection State /// The Client - public SshConnectionChangeEventArgs(bool isConnected, GenericSshClient client) + public SshConnectionChangeEventArgs(bool isConnected, GenericSshClient client) { IsConnected = isConnected; Client = client; diff --git a/src/PepperDash.Core/Comm/GenericTcpIpClient.cs b/src/PepperDash.Core/Comm/GenericTcpIpClient.cs index 16963099..e880b386 100644 --- a/src/PepperDash.Core/Comm/GenericTcpIpClient.cs +++ b/src/PepperDash.Core/Comm/GenericTcpIpClient.cs @@ -9,18 +9,18 @@ using Crestron.SimplSharp.CrestronSockets; using JsonProperty = NewtonsoftJson::Newtonsoft.Json.JsonPropertyAttribute; using Required = NewtonsoftJson::Newtonsoft.Json.Required; -namespace PepperDash.Core -{ - /// - /// A class to handle basic TCP/IP communications with a server - /// +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; } +{ + 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 @@ -41,15 +41,15 @@ namespace PepperDash.Core private string _hostname; - /// - /// Address of server - /// - public string Hostname - { - get - { - return _hostname; - } + /// + /// Address of server + /// + public string Hostname + { + get + { + return _hostname; + } set { @@ -61,77 +61,77 @@ namespace PepperDash.Core } } - /// - /// Gets or sets the Port - /// - public int Port { 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); } - } + /// + /// 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; } + /// + /// Defaults to 2000 + /// + public int BufferSize { get; set; } /// /// The actual client class /// private TCPClient _client; - /// - /// Bool showing if socket is connected - /// - public bool IsConnected + /// + /// 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 { - get { return _client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } - } + return _client == null ? SocketStatus.SOCKET_STATUS_NO_CONNECT : _client.ClientStatus; + } + } - /// - /// S+ helper for IsConnected - /// - public ushort UIsConnected - { - get { return (ushort)(IsConnected ? 1 : 0); } - } + /// + /// 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; } + } - /// - /// _client socket status Read only - /// - public SocketStatus ClientStatus - { - get - { - return _client == null ? SocketStatus.SOCKET_STATUS_NO_CONNECT : _client.ClientStatus; - } - } + /// + /// Status text shows the message associated with socket status + /// + public string ClientStatusText { get { return ClientStatus.ToString(); } } - /// - /// 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; } } + /// + /// Ushort representation of client status + /// + [Obsolete] + public ushort UClientStatus { get { return (ushort)ClientStatus; } } /// /// Connection failure reason @@ -143,14 +143,14 @@ namespace PepperDash.Core /// public bool AutoReconnect { get; set; } - /// - /// S+ helper for AutoReconnect - /// - public ushort UAutoReconnect - { - get { return (ushort)(AutoReconnect ? 1 : 0); } - set { AutoReconnect = value == 1; } - } + /// + /// 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 @@ -170,293 +170,297 @@ namespace PepperDash.Core get { return _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } } - //Lock object to prevent simulatneous connect/disconnect operations - private CCriticalSection connectLock = new CCriticalSection(); + //Lock object to prevent simulatneous connect/disconnect operations + private CCriticalSection connectLock = new CCriticalSection(); - // private Timer for auto reconnect - private CTimer RetryTimer; + // private Timer for auto reconnect + private CTimer RetryTimer; - /// - /// Constructor - /// - /// unique string to differentiate between instances - /// - /// - /// + /// + /// 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; + : 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); + 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); + } + + /// + /// Just to help S+ set the key + /// + 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(); } + } - /// - /// Constructor - /// - /// - public GenericTcpIpClient(string key) - : base(key) + /// + /// + /// + /// + public override bool Deactivate() + { + RetryTimer.Stop(); + RetryTimer.Dispose(); + if (_client != null) { - StreamDebugging = new CommunicationStreamDebugging(key); - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - AutoReconnectIntervalMs = 5000; - BufferSize = 2000; - - RetryTimer = new CTimer(o => - { - Reconnect(); - }, Timeout.Infinite); + _client.SocketStatusChange -= this.Client_SocketStatusChange; + DisconnectClient(); } + return true; + } - /// - /// Default constructor for S+ - /// - public GenericTcpIpClient() - : base(SplusKey) + /// + /// Attempts to connect to the server + /// + public void Connect() + { + if (string.IsNullOrEmpty(Hostname)) { - StreamDebugging = new CommunicationStreamDebugging(SplusKey); - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - AutoReconnectIntervalMs = 5000; - BufferSize = 2000; - - RetryTimer = new CTimer(o => - { - Reconnect(); - }, Timeout.Infinite); + Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': No address set", Key); + return; } - - /// - /// Initialize method - /// - public void Initialize(string key) + if (Port < 1 || Port > 65535) { - 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); + Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': Invalid port", 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() + try { - if (_client == null) + connectLock.Enter(); + if (IsConnected) { - 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(); + Debug.Console(1, this, "Connection already connected. Exiting Connect()"); } else { - Debug.Console(1, this, "Server connection result: {0}", c.ClientStatus); + //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(); + } + } - /// - /// Disconnects, waits and attemtps to connect again - /// + 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(); + } + } + + /// + /// Attempts to disconnect the client + /// + public void Disconnect() + { + try + { + connectLock.Enter(); + DisconnectCalledByUser = true; + + // Stop trying reconnects, if we are + RetryTimer.Stop(); + DisconnectClient(); + } + finally + { + connectLock.Leave(); + } + } + + /// + /// Does the actual disconnect business + /// + 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 => { - CrestronInvoke.BeginInvoke(o => + try { - try + connectLock.Enter(); + if (!IsConnected && AutoReconnect && !DisconnectCalledByUser && _client != null) { - connectLock.Enter(); - if (!IsConnected && AutoReconnect && !DisconnectCalledByUser && _client != null) - { - DisconnectClient(); - Debug.Console(1, this, "Attempting reconnect, status={0}", _client.ClientStatus); - RetryTimer.Reset(AutoReconnectIntervalMs); - } + 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); } - } + finally + { + connectLock.Leave(); + } + }); + } - /// - /// SendText method - /// - public void SendText(string text) + /// + /// Recieves incoming data + /// + /// + /// + void Receive(TCPClient client, int numBytes) + { + if (client != null) { - 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); + if (numBytes > 0) + { + var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); + var bytesHandler = BytesReceived; + if (bytesHandler != null) + { + if (StreamDebugging.RxStreamDebuggingIsEnabled) + { + Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); + } + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + } + var textHandler = TextReceived; + if (textHandler != null) + { + var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + + if (StreamDebugging.RxStreamDebuggingIsEnabled) + { + Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length); + } + + textHandler(this, new GenericCommMethodReceiveTextArgs(str)); + } + } + client.ReceiveDataAsync(Receive); } + } + + /// + /// General send method + /// + public void SendText(string text) + { + var bytes = Encoding.GetEncoding(28591).GetBytes(text); + // Check debug level before processing byte array + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text)); + if (_client != null) + _client.SendData(bytes, bytes.Length); + } /// /// SendEscapedText method @@ -471,37 +475,35 @@ namespace PepperDash.Core 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); - } + /// + /// Sends Bytes to the server + /// + /// + public void SendBytes(byte[] bytes) + { + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + if (_client != null) + _client.SendData(bytes, bytes.Length); + } - /// - /// Socket Status Change Handler - /// - /// - /// + /// + /// Socket Status Change Handler + /// + /// + /// void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus) + { + if (clientSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED) { - 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); - } + 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) @@ -509,31 +511,31 @@ namespace PepperDash.Core } } +/// +/// Configuration properties for TCP/SSH Connections +/// + public class TcpSshPropertiesConfig + { /// - /// Represents a TcpSshPropertiesConfig + /// Address to connect to /// - 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; } + 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; } + /// + /// Passord credential + /// + public string Password { get; set; } /// /// Defaults to 32768 @@ -556,17 +558,16 @@ namespace PepperDash.Core [JsonProperty("disableSshEcho")] public bool DisableSshEcho { get; set; } - /// - /// Default constructor - /// + /// + /// Default constructor + /// public TcpSshPropertiesConfig() - { - BufferSize = 32768; - AutoReconnect = true; - AutoReconnectIntervalMs = 5000; - Username = ""; - Password = ""; - DisableSshEcho = false; - } - } -} + { + BufferSize = 32768; + AutoReconnect = true; + AutoReconnectIntervalMs = 5000; + Username = ""; + Password = ""; + } + + } diff --git a/src/PepperDash.Core/Comm/GenericTcpIpClient_ForServer.cs b/src/PepperDash.Core/Comm/GenericTcpIpClient_ForServer.cs index 6d4958ca..a1a0887f 100644 --- a/src/PepperDash.Core/Comm/GenericTcpIpClient_ForServer.cs +++ b/src/PepperDash.Core/Comm/GenericTcpIpClient_ForServer.cs @@ -19,757 +19,755 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Generic TCP/IP client for server +/// +public class GenericTcpIpClient_ForServer : Device, IAutoReconnect { /// - /// Generic TCP/IP client for server + /// Band aid delegate for choked server /// - public class GenericTcpIpClient_ForServer : Device, IAutoReconnect + 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; } + + /// + /// Port on server + /// + public int Port { get; set; } + + /// + /// S+ helper + /// + public ushort UPort { - /// - /// Band aid delegate for choked server - /// - internal delegate void ConnectionHasHungCallbackDelegate(); + get { return Convert.ToUInt16(Port); } + set { Port = Convert.ToInt32(value); } + } - #region Events + /// + /// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class + /// + public bool SharedKeyRequired { get; set; } - //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 + /// + /// S+ helper for requires shared key bool + /// + public ushort USharedKeyRequired + { + set { - get { return Convert.ToUInt16(Port); } - set { Port = Convert.ToInt32(value); } + if (value == 1) + SharedKeyRequired = true; + else + SharedKeyRequired = false; + } + } + + /// + /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module + /// + 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; } + + /// + /// Defaults to 2000 + /// + 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 + + /// + /// Just to help S+ set the key + /// + 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(); } - /// - /// 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 + /// + /// Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name. + /// + public void Connect() + { + ConnectionCount++; + Debug.Console(2, this, "Attempting connect Count:{0}", ConnectionCount); + + + if (IsConnected) { - set - { - if (value == 1) - SharedKeyRequired = true; - else - SharedKeyRequired = false; - } + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already connected. Ignoring."); + return; } - - /// - /// 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 + if (IsTryingToConnect) { - get - { - if (Client != null) - return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; - else - return false; - } + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already trying to connect. Ignoring."); + return; } - - /// - /// S+ helper for IsConnected - /// - public ushort UIsConnected + try { - 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(); - - } + IsTryingToConnect = true; if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } - Cleanup(); - } - - /// - /// Internal call to close up client. ALWAYS use this when disconnecting. - /// - void Cleanup() - { - IsTryingToConnect = false; + 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) { - //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) + 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 => { - 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) + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Connect attempt has not finished after 30sec Count:{0}", ConnectionCount); + if (IsTryingToConnect) { - RetryTimer.Stop(); - RetryTimer = null; + IsTryingToConnect = false; + + //if (ConnectionHasHungCallback != null) + //{ + // ConnectionHasHungCallback(); + //} + //SecureClient.DisconnectFromServer(); + //CheckClosedAndTryReconnect(); } - RetryTimer = new CTimer(o => Connect(), rndTime); - } - } + }, 30000); - /// - /// Receive callback - /// - /// - /// - void Receive(TCPClient client, int numBytes) - { - if (numBytes > 0) + Debug.Console(2, this, "Making Connection Count:{0}", ConnectionCount); + Client.ConnectToServerAsync(o => { - string str = string.Empty; + Debug.Console(2, this, "ConnectToServerAsync Count:{0} Ran!", ConnectionCount); - try + if (ConnectFailTimer != null) { - 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))) + 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) { - if (SharedKeyRequired && str == "SharedKey:") + WaitingForSharedKeyResponse = true; + WaitForSharedKey = new CTimer(timer => { - Debug.Console(2, this, "Server asking for shared key, sending"); - SendText(SharedKey + "\n"); - } - else if (SharedKeyRequired && str == "Shared Key Match") + + 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) { - 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)); + OnClientReadyForcommunications(true); // Key not required } } } - catch (Exception ex) + else { - Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); + 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(); + } + } + + /// + /// + /// + 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)); + } } } - if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - client.ReceiveDataAsync(Receive); + 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 HeartbeatStart() + } + 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) { - Debug.Console(2, this, "Starting Heartbeat"); - if (HeartbeatSendTimer == null) + if (!string.IsNullOrEmpty(HeartbeatString)) { - - 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)) { - var remainingText = received.Replace(HeartbeatString, ""); - var noDelimiter = received.Trim(new char[] { '\r', '\n' }); - if (noDelimiter.Contains(HeartbeatString)) + if (HeartbeatAckTimer != null) { - 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; + HeartbeatAckTimer.Reset(HeartbeatInterval * 2); } - } - } - } - 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) => + else { - // 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); - } - }); + 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(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); - } + } } } - - /// - /// SendBytes method - /// - public void SendBytes(byte[] bytes) + catch (Exception ex) { - 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); - } - } + Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); } + return received; + } - /// - /// SocketStatusChange Callback - /// - /// - /// - void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus) + + + void HeartbeatAckTimerFail(object o) + { + try { - if (ProgramIsStopping) + + if (IsConnected) { - ProgramIsStopping = false; - return; + 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; + } + } + + /// + /// General send method + /// + public void SendText(string text) + { + if (!string.IsNullOrEmpty(text)) + { 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) + var bytes = Encoding.GetEncoding(28591).GetBytes(text); + if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) { - HeartbeatStop(); - OnClientReadyForcommunications(false); // socket has gone low - CheckClosedAndTryReconnect(); + 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(1, this, Debug.ErrorLogLevel.Error, "Error in socket status change callback. Error: {0}\r\r{1}", ex, ex.InnerException); + Debug.Console(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); } } - - /// - /// 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 } - -} \ No newline at end of file + + /// + /// + /// + 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 +} diff --git a/src/PepperDash.Core/Comm/GenericTcpIpServer.cs b/src/PepperDash.Core/Comm/GenericTcpIpServer.cs index 5cec96df..3dce8895 100644 --- a/src/PepperDash.Core/Comm/GenericTcpIpServer.cs +++ b/src/PepperDash.Core/Comm/GenericTcpIpServer.cs @@ -17,589 +17,563 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Generic TCP/IP server device +/// +public class GenericTcpIpServer : Device { + #region Events /// - /// Generic TCP/IP server device + /// Event for Receiving text /// - public class GenericTcpIpServer : Device + 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; } + + /// + /// + /// + 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; + + /// + /// 3 by default + /// + public int MonitorClientMaxFailureCount { get; set; } + + /// + /// Text representation of the Socket Status enum values for the server + /// + public string Status { - #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 { - get - { - if (myTcpServer != null) - return myTcpServer.State.ToString(); - return ServerState.SERVER_NOT_LISTENING.ToString(); - - } + if (myTcpServer != null) + return myTcpServer.State.ToString(); + return ServerState.SERVER_NOT_LISTENING.ToString(); } - /// - /// Bool showing if socket is connected - /// - public bool IsConnected + } + + /// + /// Bool showing if socket is connected + /// + public bool IsConnected + { + get { - get - { - if (myTcpServer != null) - return (myTcpServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED; + 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_CONNECTED) == ServerState.SERVER_CONNECTED : - // (UnsecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED); - } + //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 UIsConnected + /// + /// 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 { - get { return (ushort)(IsConnected ? 1 : 0); } + if (myTcpServer != null) + return (ushort)myTcpServer.NumberOfClientsConnected; + return 0; } + } - /// - /// Bool showing if socket is connected - /// - public bool IsListening + /// + /// Port Server should listen on + /// + 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 { - get + if (value == 1) + SharedKeyRequired = true; + else + SharedKeyRequired = false; + } + } + + /// + /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module. + /// If SharedKey changes while server is listening or clients are connected, disconnect and stop listening will be called + /// + 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; + } + } + + /// + /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ + /// + public int HeartbeatRequiredIntervalMs { get; set; } + + /// + /// Simpl+ Heartbeat Analog value in seconds + /// + public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatRequiredIntervalMs = (value * 1000); } } + + /// + /// String to Match for heartbeat. If null or empty any string will reset heartbeat timer + /// + 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(); + + /// + /// Defaults to 2000 + /// + 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 + /// + /// Disconnects all clients and stops the server + /// + 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+ + /// + /// + 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)) { - 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); + 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; + } - } - - /// - /// 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 + else { ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); } } - - /// - /// Listen method - /// - public void Listen() + catch { - 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; + ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); + } + } - if (myTcpServer == null) - { - myTcpServer = new TCPServer(Port, MaxClients); - if(HeartbeatRequired) - myTcpServer.SocketSendOrReceiveTimeOutInMs = (this.HeartbeatRequiredIntervalMs * 5); - + /// + /// Start listening on the specified port + /// + 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) + else { - ServerCCSection.Leave(); - ErrorLog.Error("{1} Error with Dynamic Server: {0}", ex.ToString(), Key); + 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(); } - - /// - /// StopListening method - /// - public void StopListening() + catch (Exception ex) { - 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); - } + ServerCCSection.Leave(); + ErrorLog.Error("{1} Error with Dynamic Server: {0}", ex.ToString(), Key); } + } - /// - /// Disconnects Client - /// - /// - /// - /// DisconnectClient method - /// - public void DisconnectClient(uint client) + /// + /// Stop Listening + /// + public void StopListening() + { + try { - 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"); + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Stopping Listener"); 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); + 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); + } + } - Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected All Clients"); - ConnectedClientsIndexes.Clear(); - - if (!ProgramIsStopping) + /// + /// Disconnects Client + /// + /// + 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); + } + } + /// + /// Disconnect All Clients + /// + 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 { - OnConnectionChange(); - OnServerStateChange(myTcpServer.State); //State shows both listening and connected + 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); + } } - - // var o = new { }; + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Server Status: {0}", myTcpServer.ServerSocketStatus); } - /// - /// Broadcast text from server to all connected clients - /// - /// - /// - /// BroadcastText method - /// - public void BroadcastText(string text) + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected All Clients"); + ConnectedClientsIndexes.Clear(); + + if (!ProgramIsStopping) { - 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); - } + OnConnectionChange(); + OnServerStateChange(myTcpServer.State); //State shows both listening and connected } - /// - /// Not sure this is useful in library, maybe Pro?? - /// - /// - /// - /// - /// SendTextToClient method - /// - public void SendTextToClient(string text, uint clientIndex) + // var o = new { }; + } + + /// + /// Broadcast text from server to all connected clients + /// + /// + public void BroadcastText(string text) + { + CCriticalSection CCBroadcast = new CCriticalSection(); + CCBroadcast.Enter(); + try { - try + if (ConnectedClientsIndexes.Count > 0) { byte[] b = Encoding.GetEncoding(28591).GetBytes(text); - if (myTcpServer != null && myTcpServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) + foreach (uint i in ConnectedClientsIndexes) { - if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) - myTcpServer.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); + 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()); + } } } - catch (Exception ex) + 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?? + /// + /// + /// + 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) { - Debug.Console(2, this, "Error sending text to client. Text: {1}. Error: {0}", ex.Message, text); + if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) + myTcpServer.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); } } - - //private method to check heartbeat requirements and start or reset timer - string checkHeartbeat(uint clientIndex, string received) + catch (Exception ex) { - try + 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 (HeartbeatRequired) + if (!string.IsNullOrEmpty(HeartbeatStringToMatch)) { - 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 + 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); @@ -608,200 +582,212 @@ namespace PepperDash.Core 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); + Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", HeartbeatStringToMatch, clientIndex); + // Return Heartbeat + SendTextToClient(HeartbeatStringToMatch, clientIndex); + return remainingText; } } - } - 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 ""; + 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); + } } } - - #endregion - - #region Methods - HeartbeatTimer Callback - - void HeartbeatTimer_CallbackFunction(object o) + catch (Exception ex) { - uint clientIndex = 99999; - string address = string.Empty; - try + 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 + 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)) { - clientIndex = (uint)o; - address = myTcpServer.GetAddressServerAcceptedConnectionFromForSpecificClient(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); + } + } - 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); + #endregion - if (myTcpServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) - SendTextToClient("Heartbeat not received by server, closing connection", clientIndex); + #region Methods - Socket Status Changed Callbacks + /// + /// Secure Server Socket Status Changed Callback + /// + /// + /// + /// + void TcpServer_SocketStatusChange(TCPServer server, uint clientIndex, SocketStatus serverSocketStatus) + { + try + { - var discoResult = myTcpServer.Disconnect(clientIndex); - //Debug.Console(1, this, "{0}", discoResult); - - if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) + 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); } - } - 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 (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) + 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"; @@ -845,181 +831,180 @@ namespace PepperDash.Core myTCPServer.Disconnect(); } - } + } - #endregion + #endregion - #region Methods - EventHelpers/Callbacks + #region Methods - EventHelpers/Callbacks - //Private Helper method to call the Connection Change Event - void onConnectionChange(uint clientIndex, SocketStatus clientStatus) + //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 { - 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()); + handler(this, new GenericTcpServerSocketStatusChangeEventArgs(myTcpServer, clientIndex, clientStatus)); } } + } - //Private Helper Method to call the Text Received Event - void onTextReceived(string text, uint clientIndex) + //Private Helper method to call the Connection Change Event + void OnConnectionChange() + { + if (ProgramIsStopping) { - var handler = TextReceived; - if (handler != null) - handler(this, new GenericTcpServerCommMethodReceiveTextArgs(text, clientIndex)); + return; } - - //Private Helper Method to call the Server State Change Event - void OnServerStateChange(ServerState state) + var handler = ClientConnectionChange; + if (handler != null) { - if (ProgramIsStopping) - { - return; - } - var handler = ServerStateChange; - if (handler != null) - { - handler(this, new GenericTcpServerStateChangedEventArgs(state)); - } + handler(this, new GenericTcpServerSocketStatusChangeEventArgs()); } + } - /// - /// Private Event Handler method to handle the closing of connections when the program stops - /// - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + //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) { - 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(); - } + return; } - - //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) + var handler = ServerStateChange; + if (handler != null) { - ClientReadyAfterKeyExchange.Add(clientIndex); - var handler = ServerClientReadyForCommunications; - if (handler != null) - handler(this, new GenericTcpServerSocketStatusChangeEventArgs( - this, clientIndex, myTcpServer.GetServerSocketStatusForSpecificClient(clientIndex))); + handler(this, new GenericTcpServerStateChangedEventArgs(state)); } - #endregion + } - #region Monitor Client - /// - /// Starts the monitor client cycle. Timed wait, then call RunMonitorClient - /// - void StartMonitorClient() + /// + /// 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) - { - 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 (MonitorClient != null) + MonitorClient.Disconnect(); - /// - /// If the client hangs, add to counter and maybe fire the choke event - /// - void MonitorClientHasHungCallback() + 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) { - MonitorClientFailureCount++; + 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(); - 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 - } + StartMonitorClient(); } - #endregion } + + /// + /// 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 } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/GenericUdpServer.cs b/src/PepperDash.Core/Comm/GenericUdpServer.cs index 34df1444..6a761e6c 100644 --- a/src/PepperDash.Core/Comm/GenericUdpServer.cs +++ b/src/PepperDash.Core/Comm/GenericUdpServer.cs @@ -11,364 +11,347 @@ using JsonProperty = NewtonsoftJson::Newtonsoft.Json.JsonPropertyAttribute; using PepperDash.Core.Logging; using Required = NewtonsoftJson::Newtonsoft.Json.Required; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Generic UDP Server device +/// +public class GenericUdpServer : Device, ISocketStatusWithStreamDebugging { + private const string SplusKey = "Uninitialized Udp Server"; /// - /// Generic UDP Server device + /// Object to enable stream debugging /// - 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 CommunicationStreamDebugging StreamDebugging { get; private set; } + /// + /// + /// + public event EventHandler BytesReceived; - /// - /// - /// - public event EventHandler TextReceived; + /// + /// + /// + 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. - /// + /// + /// 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 ConnectionChange; - /// - /// - /// - public event EventHandler UpdateConnectionStatus; + /// + /// + /// + public event EventHandler UpdateConnectionStatus; - /// - /// - /// - public SocketStatus ClientStatus + /// + /// + /// + public SocketStatus ClientStatus + { + get { - get - { - return Server.ServerStatus; - } + 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 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 buffefSize) + : base(key) + { + StreamDebugging = new CommunicationStreamDebugging(key); + Hostname = address; + Port = port; + BufferSize = buffefSize; + + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); + } + + /// + /// Call from S+ to initialize values + /// + /// + /// + /// + 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(); + } + + /// + /// Enables the UDP Server + /// + public void Connect() + { + if (Server == null) + { + 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); + } + + /// + /// Disabled the UDP Server + /// + 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) + { + if (StreamDebugging.RxStreamDebuggingIsEnabled) + { + Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); + } + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + } + var textHandler = TextReceived; + if (textHandler != null) + { + if (StreamDebugging.RxStreamDebuggingIsEnabled) + Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length); + textHandler(this, new GenericCommMethodReceiveTextArgs(str)); + } + } + catch (Exception ex) + { + this.LogException(ex, "GenericUdpServer Receive error"); + } + finally + { + server.ReceiveDataAsync(Receive); + } + } + + /// + /// General send method + /// + /// + public void SendText(string text) + { + var bytes = Encoding.GetEncoding(28591).GetBytes(text); + + if (IsConnected && Server != null) + { + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text)); + + Server.SendData(bytes, bytes.Length); + } + } + + /// + /// + /// + /// + public void SendBytes(byte[] bytes) + { + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + + if (IsConnected && Server != null) + Server.SendData(bytes, bytes.Length); + } + +} + +/// +/// +/// + public class GenericUdpReceiveTextExtraArgs : EventArgs + { + /// + /// + /// public string Text { get; private set; } - /// - /// - /// + /// + /// + /// public string IpAddress { get; private set; } - /// - /// - /// - public int Port { 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; @@ -383,34 +366,33 @@ namespace PepperDash.Core public GenericUdpReceiveTextExtraArgs() { } } +/// +/// +/// +public class UdpServerPropertiesConfig +{ /// /// /// - 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() { - /// - /// - /// - [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; - } + BufferSize = 32768; } } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/TcpClientConfigObject.cs b/src/PepperDash.Core/Comm/TcpClientConfigObject.cs index e2137d4a..2aec5af8 100644 --- a/src/PepperDash.Core/Comm/TcpClientConfigObject.cs +++ b/src/PepperDash.Core/Comm/TcpClientConfigObject.cs @@ -2,60 +2,59 @@ using JsonProperty = NewtonsoftJson::Newtonsoft.Json.JsonPropertyAttribute; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Client config object for TCP client with server that inherits from TcpSshPropertiesConfig and adds properties for shared key and heartbeat +/// +public class TcpClientConfigObject { /// - /// Represents a TcpClientConfigObject + /// TcpSsh Properties /// - public class TcpClientConfigObject - { - /// - /// TcpSsh Properties - /// - [JsonProperty("control")] - public ControlPropertiesConfig Control { get; set; } + [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; } + /// + /// 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; } + /// + /// 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; } + /// + /// 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; } + /// + /// 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; } + /// + /// 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; } + /// + /// 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; } - } + /// + /// Receive Queue size must be greater than 20 or defaults to 20 + /// + [JsonProperty("receiveQueueSize")] + public int ReceiveQueueSize { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/TcpServerConfigObject.cs b/src/PepperDash.Core/Comm/TcpServerConfigObject.cs index 043cf58d..b60f486f 100644 --- a/src/PepperDash.Core/Comm/TcpServerConfigObject.cs +++ b/src/PepperDash.Core/Comm/TcpServerConfigObject.cs @@ -4,57 +4,56 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Tcp Server Config object with properties for a tcp server with shared key and heartbeat capabilities +/// +public class TcpServerConfigObject { /// - /// Tcp Server Config object with properties for a tcp server with shared key and heartbeat capabilities + /// Uique key /// - 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; } - } + 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; } } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/eControlMethods.cs b/src/PepperDash.Core/Comm/eControlMethods.cs index b807fdc5..db1bcb19 100644 --- a/src/PepperDash.Core/Comm/eControlMethods.cs +++ b/src/PepperDash.Core/Comm/eControlMethods.cs @@ -4,84 +4,83 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Crestron Control Methods for a comm object +/// +public enum eControlMethod { /// - /// 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, - /// - /// 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 - } + 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, + /// + /// HTTP client + /// + Http, + /// + /// HTTPS client + /// + Https, + /// + /// Websocket client + /// + Ws, + /// + /// Secure Websocket client + /// + Wss, + /// + /// Secure TCP/IP + /// + SecureTcpIp, + /// + /// Crestron COM bridge + /// + ComBridge, + /// + /// Crestron Infinet EX device + /// + InfinetEx } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/eStreamDebuggingSetting.cs b/src/PepperDash.Core/Comm/eStreamDebuggingSetting.cs deleted file mode 100644 index f9f7eb3f..00000000 --- a/src/PepperDash.Core/Comm/eStreamDebuggingSetting.cs +++ /dev/null @@ -1,28 +0,0 @@ -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 - } -} diff --git a/src/PepperDash.Core/CommunicationExtras.cs b/src/PepperDash.Core/CommunicationExtras.cs index 1fcce75b..04e36982 100644 --- a/src/PepperDash.Core/CommunicationExtras.cs +++ b/src/PepperDash.Core/CommunicationExtras.cs @@ -2,139 +2,142 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using JsonConverter = NewtonsoftJson::Newtonsoft.Json.JsonConverterAttribute; using JsonProperty = NewtonsoftJson::Newtonsoft.Json.JsonPropertyAttribute; using StringEnumConverter = NewtonsoftJson::Newtonsoft.Json.Converters.StringEnumConverter; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// An incoming communication stream +/// +public interface ICommunicationReceiver : IKeyed { /// - /// An incoming communication stream + /// Notifies of bytes received /// - 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(); - } + event EventHandler BytesReceived; + /// + /// Notifies of text received + /// + event EventHandler TextReceived; /// - /// Defines the contract for IBasicCommunication + /// Indicates connection status /// - public interface IBasicCommunication : ICommunicationReceiver - { - /// - /// Send text to the device - /// - /// + [JsonProperty("isConnected")] + bool IsConnected { get; } + /// + /// Connect to the device + /// + void Connect(); + /// + /// Disconnect from the device + /// + void Disconnect(); +} + + /// + /// Extends with methods for sending text and bytes to a device. + /// +public interface IBasicCommunication : ICommunicationReceiver + { + /// + /// Send text to the device + /// + /// void SendText(string text); - /// - /// Send bytes to the device - /// - /// + /// + /// 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 that implements IBasicCommunication and IStreamDebugging +/// +public interface IBasicCommunicationWithStreamDebugging : IBasicCommunication, IStreamDebugging +{ - } +} +/// +/// Represents a device with stream debugging capablities +/// +public interface IStreamDebugging : IKeyed +{ /// - /// Represents a device with stream debugging capablities + /// Object to enable stream debugging /// - public interface IStreamDebugging : IKeyed - { - /// - /// Object to enable stream debugging - /// - [JsonProperty("streamDebugging")] - CommunicationStreamDebugging StreamDebugging { get; } - } + [JsonProperty("streamDebugging")] + CommunicationStreamDebugging StreamDebugging { get; } +} + /// + /// For IBasicCommunication classes that have SocketStatus. GenericSshClient, + /// GenericTcpIpClient + /// + public interface ISocketStatus : IBasicCommunication + { /// - /// For IBasicCommunication classes that have SocketStatus. GenericSshClient, - /// GenericTcpIpClient + /// Notifies of socket status changes /// - public interface ISocketStatus : IBasicCommunication - { - /// - /// Notifies of socket status changes - /// event EventHandler ConnectionChange; - /// - /// The current socket status of the client - /// - [JsonProperty("clientStatus")] - [JsonConverter(typeof(StringEnumConverter))] - SocketStatus ClientStatus { get; } - } - /// - /// Describes a device that implements ISocketStatus and IStreamDebugging + /// The current socket status of the client /// - public interface ISocketStatusWithStreamDebugging : ISocketStatus, IStreamDebugging - { + [JsonProperty("clientStatus")] + [JsonConverter(typeof(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 - /// +} + +/// +/// 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; } - } - + { /// - /// + /// 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 /// - public enum eGenericCommMethodStatusChangeType - { - /// - /// Connected - /// Connected, - /// - /// Disconnected - /// - Disconnected - } + /// + /// Disconnected + /// + Disconnected + } /// /// This delegate defines handler for IBasicCommunication status changes @@ -143,20 +146,20 @@ namespace PepperDash.Core /// public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status); + /// + /// Event args for bytes received from a communication method + /// + public class GenericCommMethodReceiveBytesArgs : EventArgs + { /// - /// + /// The bytes received /// - public class GenericCommMethodReceiveBytesArgs : EventArgs - { - /// - /// Gets or sets the Bytes - /// - public byte[] Bytes { get; private set; } + public byte[] Bytes { get; private set; } - /// - /// - /// - /// + /// + /// Constructor + /// + /// public GenericCommMethodReceiveBytesArgs(byte[] bytes) { Bytes = bytes; @@ -168,42 +171,81 @@ namespace PepperDash.Core public GenericCommMethodReceiveBytesArgs() { } } + /// + /// Event args for text received + /// + public class GenericCommMethodReceiveTextArgs : EventArgs + { /// - /// + /// The text received /// - public class GenericCommMethodReceiveTextArgs : EventArgs - { - /// - /// - /// public string Text { get; private set; } - /// - /// - /// - public string Delimiter { get; private set; } - /// - /// - /// - /// + /// + /// The delimiter used to determine the end of a message, if applicable + /// + public string Delimiter { get; private set; } + + /// + /// Constructor + /// + /// public GenericCommMethodReceiveTextArgs(string text) { Text = text; } - /// - /// - /// - /// - /// - public GenericCommMethodReceiveTextArgs(string text, string delimiter) - : this(text) - { - Delimiter = delimiter; - } - - /// - /// S+ Constructor - /// - public GenericCommMethodReceiveTextArgs() { } + /// + /// + /// + /// + /// + public GenericCommMethodReceiveTextArgs(string text, string delimiter) + :this(text) + { + Delimiter = delimiter; } -} \ No newline at end of file + + /// + /// S+ Constructor + /// + public GenericCommMethodReceiveTextArgs() { } + } + + + + /// + /// Helper class to get escaped text for debugging communication streams + /// + public class ComTextHelper + { + /// + /// Gets escaped text for a byte array + /// + /// + /// + 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 + /// + /// + /// + 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 + /// + /// + /// + public static string GetDebugText(string text) + { + return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value)); + } + } diff --git a/src/PepperDash.Core/Config/PortalConfigReader.cs b/src/PepperDash.Core/Config/PortalConfigReader.cs index b7c5c784..270e10ec 100644 --- a/src/PepperDash.Core/Config/PortalConfigReader.cs +++ b/src/PepperDash.Core/Config/PortalConfigReader.cs @@ -11,15 +11,11 @@ using JToken = NewtonsoftJson::Newtonsoft.Json.Linq.JToken; using PepperDash.Core; using Serilog.Events; +namespace PepperDash.Core.Config; - -namespace PepperDash.Core.Config -{ - - - /// - /// Reads a Portal formatted config file - /// +/// +/// Reads a Portal formatted config file +/// public class PortalConfigReader { const string template = "template"; @@ -128,31 +124,31 @@ namespace PepperDash.Core.Config 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["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)); + 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]); + // 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 (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)); @@ -175,26 +171,26 @@ namespace PepperDash.Core.Config 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 + 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++) { - 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 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); + 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; } @@ -211,9 +207,9 @@ namespace PepperDash.Core.Config /// /// Merge o2 onto o1 /// - /// - /// - /// + /// + /// + /// static JObject Merge(JObject o1, JObject o2, string path) { foreach (var o2Prop in o2) @@ -259,5 +255,4 @@ namespace PepperDash.Core.Config } return o1; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/Conversion/Convert.cs b/src/PepperDash.Core/Conversion/Convert.cs index 49f8bb94..13ef7263 100644 --- a/src/PepperDash.Core/Conversion/Convert.cs +++ b/src/PepperDash.Core/Conversion/Convert.cs @@ -4,28 +4,18 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core +namespace PepperDash.Core; + +public class EncodingHelper { - /// - /// Represents a EncodingHelper - /// - public class EncodingHelper + public static string ConvertUtf8ToAscii(string utf8String) { - /// - /// 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); - } - + return Encoding.ASCII.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length); } + + public static string ConvertUtf8ToUtf16(string utf8String) + { + return Encoding.Unicode.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length); + } + } \ No newline at end of file diff --git a/src/PepperDash.Core/CoreInterfaces.cs b/src/PepperDash.Core/CoreInterfaces.cs index 7eb565dd..89e6cdad 100644 --- a/src/PepperDash.Core/CoreInterfaces.cs +++ b/src/PepperDash.Core/CoreInterfaces.cs @@ -8,30 +8,28 @@ using Crestron.SimplSharp; using JsonProperty = NewtonsoftJson::Newtonsoft.Json.JsonPropertyAttribute; using Serilog; -namespace PepperDash.Core -{ - /// - /// Unique key interface to require a unique key for the class - /// +namespace PepperDash.Core; + +/// +/// Unique key interface to require a unique key for the class +/// public interface IKeyed { - /// - /// Gets the unique key associated with the object. - /// - [JsonProperty("key")] - string Key { get; } - } - - /// - /// Named Keyed device interface. Forces the device to have a Unique Key and a name. + /// + /// Gets the unique key associated with the object. /// - public interface IKeyName : IKeyed - { - /// - /// Gets the name associated with the current object. - /// - [JsonProperty("name")] - string Name { get; } - } + [JsonProperty("key")] + string Key { get; } +} +/// +/// Named Keyed device interface. Forces the device to have a Unique Key and a name. +/// + public interface IKeyName : IKeyed +{ + /// + /// Gets the name associated with the current object. + /// + [JsonProperty("name")] + string Name { get; } } \ No newline at end of file diff --git a/src/PepperDash.Core/Device.cs b/src/PepperDash.Core/Device.cs index 7124550e..70d4d97f 100644 --- a/src/PepperDash.Core/Device.cs +++ b/src/PepperDash.Core/Device.cs @@ -2,198 +2,194 @@ using System.Collections.Generic; using Serilog.Events; -namespace PepperDash.Core +namespace PepperDash.Core; + +//********************************************************************************************************* +/// +/// Represents a Device +/// +public class Device : IKeyName { - //********************************************************************************************************* - /// - /// 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; } + + /// + /// A place to store reference to the original config object, if any. These values should + /// NOT be used as properties on the device as they are all publicly-settable values. + /// + //public DeviceConfig Config { get; private set; } + /// + /// Helper method to check if Config exists + /// + //public bool HasConfig { get { return Config != null; } } + + 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 = ""; + } - /// - /// 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; } + /// + /// Constructor with key and name + /// + /// + /// + public Device(string key, string name) : this(key) + { + Name = name; - /// - /// A place to store reference to the original config object, if any. These values should - /// NOT be used as properties on the device as they are all publicly-settable values. - /// - //public DeviceConfig Config { get; private set; } - /// - /// Helper method to check if Config exists - /// - //public bool HasConfig { get { return Config != null; } } + } - List _PreActivationActions; - List _PostActivationActions; + //public Device(DeviceConfig config) + // : this(config.Key, config.Name) + //{ + // Config = config; + //} - /// - /// - /// - public static Device DefaultDevice { get { return _DefaultDevice; } } - static Device _DefaultDevice = new Device("Default", "Default"); + /// + /// Adds a pre activation action + /// + /// + public void AddPreActivationAction(Action act) + { + if (_PreActivationActions == null) + _PreActivationActions = new List(); + _PreActivationActions.Add(act); + } - /// - /// 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 = ""; - } + /// + /// Adds a post activation action + /// + /// + /// + /// AddPostActivationAction method + /// + public void AddPostActivationAction(Action act) + { + if (_PostActivationActions == null) + _PostActivationActions = new List(); + _PostActivationActions.Add(act); + } - /// - /// 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 => + /// + /// PreActivate method + /// + public void PreActivate() + { + if (_PreActivationActions != null) + _PreActivationActions.ForEach(a => + { + try { - 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 => + a.Invoke(); + } + catch (Exception e) { - try - { - a.Invoke(); - } - catch (Exception e) - { - Debug.LogMessage(e, "Error in PostActivationAction: " + e.Message, this); - } - }); - } + Debug.LogMessage(e, "Error in PreActivationAction: " + 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; } + /// + /// 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; + } - /// - /// Call to deactivate device - unlink events, etc. Overriding classes do not - /// need to call base.Deactivate() - /// - /// - public virtual bool Deactivate() { return true; } + /// + /// 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); + } + }); + } - /// - /// Call this method to start communications with a device. Overriding classes do not need to call base.Initialize() - /// - public virtual void Initialize() - { - } + /// + /// 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; } - /// - /// 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(); - } + /// + /// Call to deactivate device - unlink events, etc. Overriding classes do not + /// need to call base.Deactivate() + /// + /// + public virtual bool Deactivate() { return true; } - /// - /// 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); - } + /// + /// 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}". + public override string ToString() + { + return string.Format("{0} - {1}", Key, string.IsNullOrEmpty(Name) ? "---" : Name); } } \ No newline at end of file diff --git a/src/PepperDash.Core/EthernetHelper.cs b/src/PepperDash.Core/EthernetHelper.cs index 20709eb1..51372603 100644 --- a/src/PepperDash.Core/EthernetHelper.cs +++ b/src/PepperDash.Core/EthernetHelper.cs @@ -4,11 +4,11 @@ using Crestron.SimplSharp; using JsonProperty = NewtonsoftJson::Newtonsoft.Json.JsonPropertyAttribute; using Serilog.Events; -namespace PepperDash.Core -{ - /// - /// Represents a EthernetHelper - /// +namespace PepperDash.Core; + +/// +/// Represents an EthernetHelper. +/// public class EthernetHelper { /// @@ -115,5 +115,4 @@ namespace PepperDash.Core CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/EventArgs.cs b/src/PepperDash.Core/EventArgs.cs index c146a6f2..68c2be53 100644 --- a/src/PepperDash.Core/EventArgs.cs +++ b/src/PepperDash.Core/EventArgs.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core -{ +namespace PepperDash.Core; + /// /// Bool change event args /// @@ -168,5 +168,4 @@ namespace PepperDash.Core Type = type; Index = index; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/GenericRESTfulCommunications/Constants.cs b/src/PepperDash.Core/GenericRESTfulCommunications/Constants.cs index 1b78c33f..d8a09e4e 100644 --- a/src/PepperDash.Core/GenericRESTfulCommunications/Constants.cs +++ b/src/PepperDash.Core/GenericRESTfulCommunications/Constants.cs @@ -4,13 +4,13 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.GenericRESTfulCommunications -{ +namespace PepperDash.Core.GenericRESTfulCommunications; + /// /// Constants /// - public class GenericRESTfulConstants - { +public class GenericRESTfulConstants +{ /// /// Generic boolean change /// @@ -35,5 +35,4 @@ namespace PepperDash.Core.GenericRESTfulCommunications /// Error string change /// public const ushort ErrorStringChange = 203; - } } \ No newline at end of file diff --git a/src/PepperDash.Core/GenericRESTfulCommunications/GenericRESTfulClient.cs b/src/PepperDash.Core/GenericRESTfulCommunications/GenericRESTfulClient.cs index bd33e13c..16a2ee04 100644 --- a/src/PepperDash.Core/GenericRESTfulCommunications/GenericRESTfulClient.cs +++ b/src/PepperDash.Core/GenericRESTfulCommunications/GenericRESTfulClient.cs @@ -6,8 +6,8 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.Net.Http; using Crestron.SimplSharp.Net.Https; -namespace PepperDash.Core.GenericRESTfulCommunications -{ +namespace PepperDash.Core.GenericRESTfulCommunications; + /// /// Generic RESTful communication class /// @@ -42,7 +42,7 @@ namespace PepperDash.Core.GenericRESTfulCommunications /// /// /// - /// + /// public void SubmitRequest(string url, ushort port, ushort requestType, string contentType, string username, string password) { if (url.StartsWith("https:", StringComparison.OrdinalIgnoreCase)) @@ -65,7 +65,7 @@ namespace PepperDash.Core.GenericRESTfulCommunications /// /// /// - /// + /// /// /// private void SubmitRequestHttp(string url, ushort port, ushort requestType, string contentType, string username, string password) @@ -123,7 +123,7 @@ namespace PepperDash.Core.GenericRESTfulCommunications /// /// /// - /// + /// /// /// private void SubmitRequestHttps(string url, ushort port, ushort requestType, string contentType, string username, string password) @@ -252,5 +252,4 @@ namespace PepperDash.Core.GenericRESTfulCommunications StringChange(this, args); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonStandardObjects/EventArgs and Constants.cs b/src/PepperDash.Core/JsonStandardObjects/EventArgs and Constants.cs index 110587ab..668bd481 100644 --- a/src/PepperDash.Core/JsonStandardObjects/EventArgs and Constants.cs +++ b/src/PepperDash.Core/JsonStandardObjects/EventArgs and Constants.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.JsonStandardObjects -{ +namespace PepperDash.Core.JsonStandardObjects; + /// /// Constants for simpl modules /// @@ -73,5 +73,4 @@ namespace PepperDash.Core.JsonStandardObjects Type = type; Index = index; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDevice.cs b/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDevice.cs index 2ad47e27..621e99e0 100644 --- a/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDevice.cs +++ b/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDevice.cs @@ -4,8 +4,8 @@ using Crestron.SimplSharp; using PepperDash.Core.JsonToSimpl; using Serilog.Events; -namespace PepperDash.Core.JsonStandardObjects -{ +namespace PepperDash.Core.JsonStandardObjects; + /// /// Device class /// @@ -182,5 +182,4 @@ namespace PepperDash.Core.JsonStandardObjects } #endregion EventHandler Helpers - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDeviceConfig.cs b/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDeviceConfig.cs index d754a029..5d98ba5a 100644 --- a/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDeviceConfig.cs +++ b/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDeviceConfig.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.JsonStandardObjects -{ +namespace PepperDash.Core.JsonStandardObjects; + /* Convert JSON snippt to C#: http://json2csharp.com/# @@ -52,55 +52,55 @@ namespace PepperDash.Core.JsonStandardObjects /// 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); } } /// @@ -117,43 +117,43 @@ namespace PepperDash.Core.JsonStandardObjects /// 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); } } /// @@ -170,31 +170,31 @@ namespace PepperDash.Core.JsonStandardObjects /// 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); } } /// @@ -212,27 +212,27 @@ namespace PepperDash.Core.JsonStandardObjects /// 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); } } /// @@ -249,9 +249,8 @@ namespace PepperDash.Core.JsonStandardObjects /// public class RootObject { - /// - /// The collection of devices - /// + /// + /// The collection of devices + /// public List devices { get; set; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/Constants.cs b/src/PepperDash.Core/JsonToSimpl/Constants.cs index ca638bbf..a04c1966 100644 --- a/src/PepperDash.Core/JsonToSimpl/Constants.cs +++ b/src/PepperDash.Core/JsonToSimpl/Constants.cs @@ -4,78 +4,78 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.JsonToSimpl -{ +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 3-series compatible + /// + public const ushort ProgramCompatibility3SeriesChange = 3; - /// - /// Reports the if the device is 4-series compatible - /// - public const ushort ProgramCompatibility4SeriesChange = 4; + /// + /// 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; + /// + /// 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 root directory change + /// + public const ushort RootDirectoryChange = 206; - /// - /// Reports the room ID change - /// - public const ushort RoomIdChange = 207; + /// + /// Reports the room ID change + /// + public const ushort RoomIdChange = 207; - /// - /// Reports the room name change - /// - public const ushort RoomNameChange = 208; + /// + /// Reports the room name change + /// + public const ushort RoomNameChange = 208; } /// @@ -88,33 +88,33 @@ namespace PepperDash.Core.JsonToSimpl /// 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; @@ -127,17 +127,16 @@ namespace PepperDash.Core.JsonToSimpl /// public enum SPlusType { - /// - /// Digital - /// + /// + /// Digital + /// Digital, - /// - /// Analog - /// - Analog, - /// - /// String - /// - String - } -} \ No newline at end of file + /// + /// Analog + /// + Analog, + /// + /// String + /// + String + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/Global.cs b/src/PepperDash.Core/JsonToSimpl/Global.cs index 8d71c5fb..39633a61 100644 --- a/src/PepperDash.Core/JsonToSimpl/Global.cs +++ b/src/PepperDash.Core/JsonToSimpl/Global.cs @@ -7,11 +7,11 @@ using Serilog.Events; //using PepperDash.Core; -namespace PepperDash.Core.JsonToSimpl -{ - /// - /// The global class to manage all the instances of JsonToSimplMaster - /// +namespace PepperDash.Core.JsonToSimpl; + +/// +/// The global class to manage all the instances of JsonToSimplMaster +/// public class J2SGlobal { static List Masters = new List(); @@ -22,10 +22,7 @@ namespace PepperDash.Core.JsonToSimpl /// master, this will fail /// /// New master to add - /// - /// - /// AddMaster method - /// + /// public static void AddMaster(JsonToSimplMaster master) { if (master == null) @@ -59,5 +56,4 @@ namespace PepperDash.Core.JsonToSimpl { return Masters.FirstOrDefault(m => m.UniqueID.Equals(file, StringComparison.OrdinalIgnoreCase)); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplArrayLookupChild.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplArrayLookupChild.cs index 559fc87d..f49a4b77 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplArrayLookupChild.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplArrayLookupChild.cs @@ -5,20 +5,20 @@ using System.Linq; using JArray = NewtonsoftJson::Newtonsoft.Json.Linq.JArray; using Serilog.Events; -namespace PepperDash.Core.JsonToSimpl -{ - /// - /// Represents a JsonToSimplArrayLookupChild - /// +namespace PepperDash.Core.JsonToSimpl; + +/// +/// Used to interact with an array of values with the S+ modules +/// public class JsonToSimplArrayLookupChild : JsonToSimplChildObjectBase { - /// - /// - /// + /// + /// + /// public string SearchPropertyName { get; set; } - /// - /// - /// + /// + /// + /// public string SearchPropertyValue { get; set; } int ArrayIndex; @@ -78,10 +78,9 @@ namespace PepperDash.Core.JsonToSimpl PathSuffix == null ? "" : PathSuffix); } - /// - /// ProcessAll method - /// - /// + /// + /// Process all values + /// public override void ProcessAll() { if (FindInArray()) @@ -161,5 +160,4 @@ namespace PepperDash.Core.JsonToSimpl return false; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplChildObjectBase.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplChildObjectBase.cs index e7da9c9c..2c1afd06 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplChildObjectBase.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplChildObjectBase.cs @@ -5,29 +5,29 @@ using System.Collections.Generic; using System.Linq; using JValue = NewtonsoftJson::Newtonsoft.Json.Linq.JValue; -namespace PepperDash.Core.JsonToSimpl -{ - /// - /// Base class for JSON objects - /// +namespace PepperDash.Core.JsonToSimpl; + +/// +/// Base class for JSON objects +/// public abstract class JsonToSimplChildObjectBase : IKeyed { - /// - /// Notifies of bool change - /// + /// + /// Notifies of bool change + /// public event EventHandler BoolChange; - /// - /// Notifies of ushort change - /// + /// + /// Notifies of ushort change + /// public event EventHandler UShortChange; - /// - /// Notifies of string change - /// + /// + /// Notifies of string change + /// public event EventHandler StringChange; - /// - /// Delegate to get all values - /// + /// + /// Delegate to get all values + /// public SPlusValuesDelegate GetAllValuesDelegate { get; set; } /// @@ -35,9 +35,9 @@ namespace PepperDash.Core.JsonToSimpl /// public SPlusValuesDelegate SetAllPathsDelegate { get; set; } - /// - /// Gets or sets the Key - /// + /// + /// Unique identifier for instance + /// public string Key { get; protected set; } /// @@ -51,33 +51,33 @@ namespace PepperDash.Core.JsonToSimpl /// public string PathSuffix { get; protected set; } - /// - /// Gets or sets the LinkedToObject - /// + /// + /// Indicates if the instance is linked to an object + /// public bool LinkedToObject { get; protected set; } - /// - /// Reference to Master instance - /// + /// + /// 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 - /// + /// + /// 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 - /// + /// + /// Paths to string values in JSON structure + /// protected Dictionary StringPaths = new Dictionary(); /// /// Call this before doing anything else /// - /// + /// /// /// /// @@ -94,13 +94,10 @@ namespace PepperDash.Core.JsonToSimpl Debug.Console(1, "JSON Child [{0}] cannot link to master {1}", key, masterUniqueId); } - /// - /// Sets the path prefix for the object - /// - /// - /// - /// SetPathPrefix method - /// + /// + /// Sets the path prefix for the object + /// + /// public void SetPathPrefix(string pathPrefix) { PathPrefix = pathPrefix; @@ -175,18 +172,18 @@ namespace PepperDash.Core.JsonToSimpl } // 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; } + 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); + 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) @@ -277,69 +274,54 @@ namespace PepperDash.Core.JsonToSimpl 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); @@ -369,12 +351,12 @@ namespace PepperDash.Core.JsonToSimpl // Helpers for events //****************************************************************************************** - /// - /// Event helper - /// - /// - /// - /// + /// + /// Event helper + /// + /// + /// + /// protected void OnBoolChange(bool state, ushort index, ushort type) { var handler = BoolChange; @@ -387,12 +369,12 @@ namespace PepperDash.Core.JsonToSimpl } //****************************************************************************************** - /// - /// Event helper - /// - /// - /// - /// + /// + /// Event helper + /// + /// + /// + /// protected void OnUShortChange(ushort state, ushort index, ushort type) { var handler = UShortChange; @@ -404,12 +386,12 @@ namespace PepperDash.Core.JsonToSimpl } } - /// - /// Event helper - /// - /// - /// - /// + /// + /// Event helper + /// + /// + /// + /// protected void OnStringChange(string value, ushort index, ushort type) { var handler = StringChange; @@ -420,5 +402,4 @@ namespace PepperDash.Core.JsonToSimpl StringChange(this, args); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplFileMaster.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplFileMaster.cs index bf44e2b2..a9fa03cd 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplFileMaster.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplFileMaster.cs @@ -11,284 +11,280 @@ using Formatting = NewtonsoftJson::Newtonsoft.Json.Formatting; using JObject = NewtonsoftJson::Newtonsoft.Json.Linq.JObject; using JValue = NewtonsoftJson::Newtonsoft.Json.Linq.JValue; -namespace PepperDash.Core.JsonToSimpl +namespace PepperDash.Core.JsonToSimpl; + +/// +/// Represents a JSON file that can be read and written to +/// +public class JsonToSimplFileMaster : JsonToSimplMaster { /// - /// Represents a JSON file that can be read and written to + /// Sets the filepath as well as registers this with the Global.Masters list /// - public class JsonToSimplFileMaster : JsonToSimplMaster + public string Filepath { get; private set; } + + /// + /// Filepath to the actual file that will be read (Portal or local) + /// + public string ActualFilePath { get; private set; } + + /// + /// + /// + 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() { - /// - /// 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); - /// - /// Read, evaluate and udpate status - /// - public void EvaluateFile(string filepath) - { - try + 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)) { - OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange); + OnStringChange(roomId, 0, JsonToSimplConstants.RoomIdChange); + } - var dirSeparator = Path.DirectorySeparatorChar; - var dirSeparatorAlt = Path.AltDirectorySeparatorChar; + // get the roomName + var roomName = Crestron.SimplSharp.InitialParametersClass.RoomName; + if (!string.IsNullOrEmpty(roomName)) + { + OnStringChange(roomName, 0, JsonToSimplConstants.RoomNameChange); + } - var series = CrestronEnvironment.ProgramCompatibility; + 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; + } - var is3Series = (eCrestronSeries.Series3 == (series & eCrestronSeries.Series3)); - OnBoolChange(is3Series, 0, - JsonToSimplConstants.ProgramCompatibility3SeriesChange); + 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); - var is4Series = (eCrestronSeries.Series4 == (series & eCrestronSeries.Series4)); - OnBoolChange(is4Series, 0, - JsonToSimplConstants.ProgramCompatibility4SeriesChange); + 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; + } - var isServer = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server; - OnBoolChange(isServer, 0, - JsonToSimplConstants.DevicePlatformValueChange); + // get file directory and name to search + var fileDirectory = Path.GetDirectoryName(Filepath); + var fileName = Path.GetFileName(Filepath); - // get the roomID - var roomId = Crestron.SimplSharp.InitialParametersClass.RoomId; - if (!string.IsNullOrEmpty(roomId)) + 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) { - 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"); + var msg = string.Format("JSON file not found: {0}", Filepath); + OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange); + CrestronConsole.PrintLine(msg); + ErrorLog.Error(msg); return; } - // get file directory and name to search - var fileDirectory = Path.GetDirectoryName(Filepath); - var fileName = Path.GetFileName(Filepath); + // \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); - 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); + 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); + 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); + var json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII); - JsonObject = JObject.Parse(json); - foreach (var child in Children) - child.ProcessAll(); + 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); - } + OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange); } - catch (Exception e) + else { - 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); + OnStringChange(string.Format("'{0}' not found", fileDirectory), 0, JsonToSimplConstants.StringValueChange); + Debug.Console(1, "'{0}' not found", fileDirectory); } } - - - /// - /// Sets the debug level - /// - /// - /// - /// setDebugLevel method - /// - public void setDebugLevel(uint level) + catch (Exception e) { - Debug.SetDebugLevel(level); + 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 + /// + /// + 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(); } - /// - /// Saves the values to the file - /// - public override void Save() + if (UnsavedValues == null || UnsavedValues.Count == 0) { - // 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}] No updated values to save. Skipping", UniqueID); + return; + } + lock (FileLock) + { + Debug.Console(1, "Saving"); + foreach (var path in UnsavedValues.Keys) { - 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]); - } + 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); } - using (StreamWriter sw = new StreamWriter(ActualFilePath)) + else // No token. Let's make one { - 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; - } + //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; } } } diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplFixedPathObject.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplFixedPathObject.cs index 9fa8ba01..6338e309 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplFixedPathObject.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplFixedPathObject.cs @@ -1,18 +1,17 @@  -namespace PepperDash.Core.JsonToSimpl -{ - /// - /// Represents a JsonToSimplFixedPathObject - /// +namespace PepperDash.Core.JsonToSimpl; + +/// +/// +/// public class JsonToSimplFixedPathObject : JsonToSimplChildObjectBase { - /// - /// Constructor - /// + /// + /// Constructor + /// public JsonToSimplFixedPathObject() { this.LinkedToObject = true; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplGenericMaster.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplGenericMaster.cs index c065f577..151773d9 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplGenericMaster.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplGenericMaster.cs @@ -6,35 +6,35 @@ using Crestron.SimplSharp; using JObject = NewtonsoftJson::Newtonsoft.Json.Linq.JObject; using JValue = NewtonsoftJson::Newtonsoft.Json.Linq.JValue; -namespace PepperDash.Core.JsonToSimpl -{ - /// - /// Represents a JsonToSimplGenericMaster - /// +namespace PepperDash.Core.JsonToSimpl; + +/// +/// Generic Master +/// 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 - /// + /// + /// Callback action for saving + /// public Action SaveCallback { get; set; } /*****************************************************************************************/ /// - /// SIMPL+ default constructor. - /// + /// SIMPL+ default constructor. + /// public JsonToSimplGenericMaster() - { + { } /// @@ -85,7 +85,7 @@ namespace PepperDash.Core.JsonToSimpl public override void Save() { // this code is duplicated in the other masters!!!!!!!!!!!!! - UnsavedValues = new Dictionary(); + UnsavedValues = new Dictionary(); // Make each child update their values into master object foreach (var child in Children) { @@ -121,5 +121,4 @@ namespace PepperDash.Core.JsonToSimpl else Debug.Console(0, this, "WARNING: No save callback defined."); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplMaster.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplMaster.cs index fcf6e0f8..2eb2a1d7 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplMaster.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplMaster.cs @@ -11,29 +11,29 @@ using JValue = NewtonsoftJson::Newtonsoft.Json.Linq.JValue; using JsonSerializationException = NewtonsoftJson::Newtonsoft.Json.JsonSerializationException; using JsonTextReader = NewtonsoftJson::Newtonsoft.Json.JsonTextReader; -namespace PepperDash.Core.JsonToSimpl -{ - /// - /// Abstract base class for JsonToSimpl interactions - /// +namespace PepperDash.Core.JsonToSimpl; + +/// +/// Abstract base class for JsonToSimpl interactions +/// public abstract class JsonToSimplMaster : IKeyed { - /// - /// Notifies of bool change - /// + /// + /// Notifies of bool change + /// public event EventHandler BoolChange; - /// - /// Notifies of ushort change - /// + /// + /// Notifies of ushort change + /// public event EventHandler UshrtChange; - /// - /// Notifies of string change - /// + /// + /// Notifies of string change + /// public event EventHandler StringChange; - /// - /// A collection of associated child modules - /// + /// + /// A collection of associated child modules + /// protected List Children = new List(); /*****************************************************************************************/ @@ -43,9 +43,9 @@ namespace PepperDash.Core.JsonToSimpl /// public string Key { get { return UniqueID; } } - /// - /// Gets or sets the UniqueID - /// + /// + /// A unique ID + /// public string UniqueID { get; protected set; } /// @@ -87,9 +87,9 @@ namespace PepperDash.Core.JsonToSimpl } } - /// - /// Gets or sets the JsonObject - /// + /// + /// + /// public JObject JsonObject { get; protected set; } /*****************************************************************************************/ @@ -149,9 +149,9 @@ namespace PepperDash.Core.JsonToSimpl //Debug.Console(0, "Master[{0}] Unsaved size={1}", UniqueID, UnsavedValues.Count); } - /// - /// Saves the file - /// + /// + /// Saves the file + /// public abstract void Save(); @@ -160,14 +160,14 @@ namespace PepperDash.Core.JsonToSimpl /// public static class JsonFixes { - /// - /// Deserializes a string into a JObject - /// - /// - /// + /// + /// Deserializes a string into a JObject + /// + /// + /// public static JObject ParseObject(string json) { - using (var reader = new JsonTextReader(new System.IO.StringReader(json))) + using (var reader = new JsonTextReader(new System.IO.StringReader(json))) { var startDepth = reader.Depth; var obj = JObject.Load(reader); @@ -177,18 +177,15 @@ namespace PepperDash.Core.JsonToSimpl } } - /// - /// Deserializes a string into a JArray - /// - /// - /// - /// - /// ParseArray method - /// + /// + /// Deserializes a string into a JArray + /// + /// + /// public static JArray ParseArray(string json) { - using (var reader = new JsonTextReader(new System.IO.StringReader(json))) + using (var reader = new JsonTextReader(new System.IO.StringReader(json))) { var startDepth = reader.Depth; var obj = JArray.Load(reader); @@ -231,12 +228,12 @@ namespace PepperDash.Core.JsonToSimpl } } - /// - /// Helper event - /// - /// - /// - /// + /// + /// Helper event + /// + /// + /// + /// protected void OnStringChange(string value, ushort index, ushort type) { if (StringChange != null) @@ -247,4 +244,3 @@ namespace PepperDash.Core.JsonToSimpl } } } -} diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplPortalFileMaster.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplPortalFileMaster.cs index acadc99a..caba1c9b 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplPortalFileMaster.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplPortalFileMaster.cs @@ -9,22 +9,22 @@ using JObject = NewtonsoftJson::Newtonsoft.Json.Linq.JObject; using JValue = NewtonsoftJson::Newtonsoft.Json.Linq.JValue; using PepperDash.Core.Config; -namespace PepperDash.Core.JsonToSimpl +namespace PepperDash.Core.JsonToSimpl; + +/// +/// Portal File Master +/// +public class JsonToSimplPortalFileMaster : JsonToSimplMaster { - /// - /// 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; } + /// + /// File path of the actual file being read (Portal or local) + /// + public string ActualFilePath { get; private set; } /*****************************************************************************************/ /** Privates **/ @@ -36,10 +36,10 @@ namespace PepperDash.Core.JsonToSimpl /*****************************************************************************************/ /// - /// SIMPL+ default constructor. - /// + /// SIMPL+ default constructor. + /// public JsonToSimplPortalFileMaster() - { + { } /// @@ -67,7 +67,7 @@ namespace PepperDash.Core.JsonToSimpl if (actualLocalFile != null) { ActualFilePath = actualLocalFile.FullName; - OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); + OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); } // If the local file does not exist, then read the portal file xyz.json // and create the local. @@ -81,7 +81,7 @@ namespace PepperDash.Core.JsonToSimpl // got the portal file, hand off to the merge / save method PortalConfigReader.ReadAndMergeFileIfNecessary(actualPortalFile.FullName, newLocalPath); ActualFilePath = newLocalPath; - OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); + OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); } else { @@ -194,4 +194,3 @@ namespace PepperDash.Core.JsonToSimpl } } } -} diff --git a/src/PepperDash.Core/Logging/CrestronEnricher.cs b/src/PepperDash.Core/Logging/CrestronEnricher.cs index c25306ca..1f879925 100644 --- a/src/PepperDash.Core/Logging/CrestronEnricher.cs +++ b/src/PepperDash.Core/Logging/CrestronEnricher.cs @@ -7,37 +7,30 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Core.Logging +namespace PepperDash.Core.Logging; + +public class CrestronEnricher : ILogEventEnricher { - /// - /// Represents a CrestronEnricher - /// - public class CrestronEnricher : ILogEventEnricher + static readonly string _appName; + + static CrestronEnricher() { - static readonly string _appName; - - static CrestronEnricher() + switch (CrestronEnvironment.DevicePlatform) { - 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); + case eDevicePlatform.Appliance: + _appName = $"App {InitialParametersClass.ApplicationNumber}"; + break; + case eDevicePlatform.Server: + _appName = $"{InitialParametersClass.RoomId}"; + break; } } + + + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) + { + var property = propertyFactory.CreateProperty("App", _appName); + + logEvent.AddOrUpdateProperty(property); + } } diff --git a/src/PepperDash.Core/Logging/Debug.cs b/src/PepperDash.Core/Logging/Debug.cs index 49d55eb4..6e4fb37d 100644 --- a/src/PepperDash.Core/Logging/Debug.cs +++ b/src/PepperDash.Core/Logging/Debug.cs @@ -20,8 +20,8 @@ using Serilog.Formatting.Compact; using Serilog.Formatting.Json; using Serilog.Templates; -namespace PepperDash.Core -{ +namespace PepperDash.Core; + /// /// public static class Debug @@ -1238,6 +1238,5 @@ namespace PepperDash.Core /// None /// None, - } } } \ No newline at end of file diff --git a/src/PepperDash.Core/Logging/DebugConsoleSink.cs b/src/PepperDash.Core/Logging/DebugConsoleSink.cs index 6363caa5..5e32a8a5 100644 --- a/src/PepperDash.Core/Logging/DebugConsoleSink.cs +++ b/src/PepperDash.Core/Logging/DebugConsoleSink.cs @@ -9,56 +9,45 @@ using System.IO; using System.Text; -namespace PepperDash.Core +namespace PepperDash.Core; + +public class DebugConsoleSink : ILogEventSink { - /// - /// Represents a DebugConsoleSink - /// - public class DebugConsoleSink : ILogEventSink + private readonly ITextFormatter _textFormatter; + + public void Emit(LogEvent logEvent) { - private readonly ITextFormatter _textFormatter; + if (!Debug.IsRunningOnAppliance) return; - /// - /// Emit method - /// - public void Emit(LogEvent logEvent) + /*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) { - if (!Debug.IsRunningOnAppliance) return; + message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue,3}]: {logEvent.RenderMessage()}"; + }*/ - /*string message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}]{logEvent.RenderMessage()}"; + var buffer = new StringWriter(new StringBuilder(256)); - 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()}"; - }*/ + _textFormatter.Format(logEvent, buffer); - 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(); - } + var message = buffer.ToString(); + CrestronConsole.PrintLine(message); } - public static class DebugConsoleSinkExtensions + public DebugConsoleSink(ITextFormatter formatProvider ) { - /// - /// DebugConsoleSink method - /// - public static LoggerConfiguration DebugConsoleSink( - this LoggerSinkConfiguration loggerConfiguration, - ITextFormatter formatProvider = null) - { - return loggerConfiguration.Sink(new DebugConsoleSink(formatProvider)); - } + _textFormatter = formatProvider ?? new JsonFormatter(); } } + +public static class DebugConsoleSinkExtensions +{ + public static LoggerConfiguration DebugConsoleSink( + this LoggerSinkConfiguration loggerConfiguration, + ITextFormatter formatProvider = null) + { + return loggerConfiguration.Sink(new DebugConsoleSink(formatProvider)); + } +} diff --git a/src/PepperDash.Core/Logging/DebugContext.cs b/src/PepperDash.Core/Logging/DebugContext.cs index cdea6837..117140ab 100644 --- a/src/PepperDash.Core/Logging/DebugContext.cs +++ b/src/PepperDash.Core/Logging/DebugContext.cs @@ -9,288 +9,275 @@ using Formatting = NewtonsoftJson::Newtonsoft.Json.Formatting; using JsonConvert = NewtonsoftJson::Newtonsoft.Json.JsonConvert; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Represents a debugging context +/// +public class DebugContext { /// - /// Represents a debugging context + /// 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 class DebugContext + 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 + /// + /// + /// + public static DebugContext GetDebugContext(string key) { - /// - /// 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) { - var context = Contexts.FirstOrDefault(c => c.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); - if (context == null) - { - context = new DebugContext(key); - Contexts.Add(context); - } - return context; + 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); } - /// - /// Do not use. For S+ access. - /// - public DebugContext() { } + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; - DebugContext(string key) + LoadMemory(); + } + + /// + /// Used to save memory when shutting down + /// + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping) { - Key = key; - if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SimplSharpPro) + if (SaveTimer != null) { - // Add command to console - CrestronConsole.AddNewConsoleCommand(SetDebugFromConsole, "appdebug", - "appdebug:P [0-2]: Sets the application's console debug message level", - ConsoleAccessLevelEnum.AccessOperator); + SaveTimer.Stop(); + SaveTimer = null; + } + Console(0, "Saving debug settings"); + SaveMemory(); + } + } + + /// + /// Callback for console command + /// + /// + public void SetDebugFromConsole(string levelString) + { + try + { + if (string.IsNullOrEmpty(levelString.Trim())) + { + CrestronConsole.ConsoleCommandResponse("AppDebug level = {0}", SaveData.Level); + return; } - CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; - - LoadMemory(); + SetDebugLevel(Convert.ToInt32(levelString)); } - - /// - /// Used to save memory when shutting down - /// - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + catch { - if (programEventType == eProgramStatusEventType.Stopping) - { - if (SaveTimer != null) - { - SaveTimer.Stop(); - SaveTimer = null; - } - Console(0, "Saving debug settings"); - SaveMemory(); - } + CrestronConsole.PrintLine("Usage: appdebug:P [0-2]"); } + } - /// - /// Callback for console command - /// - /// - /// - /// SetDebugFromConsole method - /// - public void SetDebugFromConsole(string levelString) + /// + /// Sets the debug level + /// + /// Valid values 0 (no debug), 1 (critical), 2 (all messages) + public void SetDebugLevel(int level) + { + if (level <= 2) { - try - { - if (string.IsNullOrEmpty(levelString.Trim())) - { - CrestronConsole.ConsoleCommandResponse("AppDebug level = {0}", SaveData.Level); - return; - } + SaveData.Level = level; + SaveMemoryOnTimeout(); - SetDebugLevel(Convert.ToInt32(levelString)); - } - catch - { - CrestronConsole.PrintLine("Usage: appdebug:P [0-2]"); - } + CrestronConsole.PrintLine("[Application {0}], Debug level set to {1}", + InitialParametersClass.ApplicationNumber, SaveData.Level); } + } - /// - /// Sets the debug level - /// - /// Valid values 0 (no debug), 1 (critical), 2 (all messages) - /// - /// SetDebugLevel method - /// - public void SetDebugLevel(int 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)); + } + + /// + /// Appends a device Key to the beginning of a message + /// + 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) { - 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); + var str = string.Format("[{0}] {1}", dev.Key, string.Format(format, items)); + Console(level, str); + LogError(errorLogLevel, str); } } /// /// /// - public class DebugContextSaveData + /// + /// + /// + /// + public void Console(uint level, Debug.ErrorLogLevel errorLogLevel, + string format, params object[] items) { - /// - /// - /// - public int Level { get; set; } + if (SaveData.Level >= level) + { + var str = string.Format(format, items); + Console(level, str); + LogError(errorLogLevel, str); + } } + + /// + /// + /// + /// + /// + 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; } } \ No newline at end of file diff --git a/src/PepperDash.Core/Logging/DebugCrestronLoggerSink.cs b/src/PepperDash.Core/Logging/DebugCrestronLoggerSink.cs index 76859209..a2e82ec8 100644 --- a/src/PepperDash.Core/Logging/DebugCrestronLoggerSink.cs +++ b/src/PepperDash.Core/Logging/DebugCrestronLoggerSink.cs @@ -3,33 +3,26 @@ using Crestron.SimplSharp.CrestronLogger; using Serilog.Core; using Serilog.Events; -namespace PepperDash.Core.Logging +namespace PepperDash.Core.Logging; + +public class DebugCrestronLoggerSink : ILogEventSink { - /// - /// Represents a DebugCrestronLoggerSink - /// - public class DebugCrestronLoggerSink : ILogEventSink + public void Emit(LogEvent logEvent) { - /// - /// 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) { - 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); + message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue}]: {logEvent.RenderMessage()}"; } - public DebugCrestronLoggerSink() - { - CrestronLogger.Initialize(1, LoggerModeEnum.RM); - } + CrestronLogger.WriteToLog(message, (uint)logEvent.Level); + } + + public DebugCrestronLoggerSink() + { + CrestronLogger.Initialize(1, LoggerModeEnum.RM); } } diff --git a/src/PepperDash.Core/Logging/DebugErrorLogSink.cs b/src/PepperDash.Core/Logging/DebugErrorLogSink.cs index 9ab4dc6b..3c2e6761 100644 --- a/src/PepperDash.Core/Logging/DebugErrorLogSink.cs +++ b/src/PepperDash.Core/Logging/DebugErrorLogSink.cs @@ -9,63 +9,56 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Core.Logging +namespace PepperDash.Core.Logging; + +public class DebugErrorLogSink : ILogEventSink { - /// - /// Represents a DebugErrorLogSink - /// - public class DebugErrorLogSink : ILogEventSink + private ITextFormatter _formatter; + + private Dictionary> _errorLogMap = new Dictionary> { - private ITextFormatter _formatter; + { 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) } + }; + public void Emit(LogEvent logEvent) + { + string message; - private Dictionary> _errorLogMap = new Dictionary> + if (_formatter == null) { - { 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) + 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 { - string message; + var buffer = new StringWriter(new StringBuilder(256)); - if (_formatter == null) - { - var programId = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance - ? $"App {InitialParametersClass.ApplicationNumber}" - : $"Room {InitialParametersClass.RoomId}"; + _formatter.Format(logEvent, buffer); - 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); + message = buffer.ToString(); } - public DebugErrorLogSink(ITextFormatter formatter = null) + if(!_errorLogMap.TryGetValue(logEvent.Level, out var handler)) { - _formatter = formatter; + return; } + + handler(message); + } + + public DebugErrorLogSink(ITextFormatter formatter = null) + { + _formatter = formatter; } } diff --git a/src/PepperDash.Core/Logging/DebugExtensions.cs b/src/PepperDash.Core/Logging/DebugExtensions.cs index ccee4943..7ae40d97 100644 --- a/src/PepperDash.Core/Logging/DebugExtensions.cs +++ b/src/PepperDash.Core/Logging/DebugExtensions.cs @@ -2,112 +2,72 @@ using Serilog.Events; using Log = PepperDash.Core.Debug; -namespace PepperDash.Core.Logging +namespace PepperDash.Core.Logging; + +public static class DebugExtensions { - public static class DebugExtensions + public static void LogException(this IKeyed device, Exception ex, string message, params object[] args) { - /// - /// LogException method - /// - public static void LogException(this IKeyed device, Exception ex, string message, params object[] args) - { - Log.LogMessage(ex, message, device: device, args); - } + Log.LogMessage(ex, message, device, args); + } - /// - /// LogVerbose method - /// - public static void LogVerbose(this IKeyed device, Exception ex, string message, params object[] args) - { - Log.LogVerbose(ex, device, message, args); - } + public static void LogVerbose(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Verbose, ex, message, device, args); + } - /// - /// LogVerbose method - /// - public static void LogVerbose(this IKeyed device, string message, params object[] args) - { - Log.LogVerbose(device, message, args); - } + public static void LogVerbose(this IKeyed device, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Verbose, 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); - } + public static void LogDebug(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Debug, ex, message, device, args); + } - /// - /// LogDebug method - /// - public static void LogDebug(this IKeyed device, string message, params object[] args) - { - Log.LogDebug(device, message, args); - } + public static void LogDebug(this IKeyed device, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Debug, 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); - } + public static void LogInformation(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Information, ex, message, device, args); + } - /// - /// LogInformation method - /// - public static void LogInformation(this IKeyed device, string message, params object[] args) - { - Log.LogInformation(device, message, args); - } + public static void LogInformation(this IKeyed device, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Information, 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); - } + public static void LogWarning(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Warning, ex, message, device, args); + } - /// - /// LogWarning method - /// - public static void LogWarning(this IKeyed device, string message, params object[] args) - { - Log.LogWarning(device, message, args); - } + public static void LogWarning(this IKeyed device, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Warning, 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); - } + public static void LogError(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Error, ex, message, device, args); + } - /// - /// LogError method - /// - public static void LogError(this IKeyed device, string message, params object[] args) - { - Log.LogError(device, message, args); - } + public static void LogError(this IKeyed device, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Error, 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); - } + public static void LogFatal(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Fatal, ex, message, device, args); + } - /// - /// LogFatal method - /// - public static void LogFatal(this IKeyed device, string message, params object[] args) - { - Log.LogFatal(device, message, args); - } + public static void LogFatal(this IKeyed device, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Fatal, device, message, args); } } diff --git a/src/PepperDash.Core/Logging/DebugMemory.cs b/src/PepperDash.Core/Logging/DebugMemory.cs index 327d04b4..da327f77 100644 --- a/src/PepperDash.Core/Logging/DebugMemory.cs +++ b/src/PepperDash.Core/Logging/DebugMemory.cs @@ -4,25 +4,25 @@ using System.Collections.Generic; using Crestron.SimplSharp; using JsonProperty = NewtonsoftJson::Newtonsoft.Json.JsonPropertyAttribute; -namespace PepperDash.Core.Logging -{ - /// - /// Represents a DebugContextCollection - /// +namespace PepperDash.Core.Logging; + +/// +/// Class to persist current Debug settings across program restarts +/// public class DebugContextCollection { - /// - /// To prevent threading issues with the DeviceDebugSettings collection - /// - private readonly CCriticalSection _deviceDebugSettingsLock; + /// + /// 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; } + /// + /// Collection of the debug settings for each device where the dictionary key is the device key + /// + [JsonProperty("deviceDebugSettings")] + private Dictionary DeviceDebugSettings { get; set; } /// @@ -30,8 +30,8 @@ namespace PepperDash.Core.Logging /// public DebugContextCollection() { - _deviceDebugSettingsLock = new CCriticalSection(); - DeviceDebugSettings = new Dictionary(); + _deviceDebugSettingsLock = new CCriticalSection(); + DeviceDebugSettings = new Dictionary(); _items = new Dictionary(); } @@ -67,46 +67,40 @@ namespace PepperDash.Core.Logging } - /// - /// sets the settings for a device or creates a new entry - /// - /// - /// - /// - /// - /// SetDebugSettingsForKey method - /// - public void SetDebugSettingsForKey(string deviceKey, object settings) + /// + /// sets the settings for a device or creates a new entry + /// + /// + /// + /// + public void SetDebugSettingsForKey(string deviceKey, object settings) + { + try { - try - { - _deviceDebugSettingsLock.Enter(); + _deviceDebugSettingsLock.Enter(); - if (DeviceDebugSettings.ContainsKey(deviceKey)) - { - DeviceDebugSettings[deviceKey] = settings; - } - else - DeviceDebugSettings.Add(deviceKey, settings); - } - finally + if (DeviceDebugSettings.ContainsKey(deviceKey)) { - _deviceDebugSettingsLock.Leave(); + DeviceDebugSettings[deviceKey] = settings; } + else + DeviceDebugSettings.Add(deviceKey, settings); } - - /// - /// Gets the device settings for a device by key or returns null - /// - /// - /// - /// - /// GetDebugSettingsForKey method - /// - public object GetDebugSettingsForKey(string deviceKey) + finally { - return DeviceDebugSettings[deviceKey]; + _deviceDebugSettingsLock.Leave(); } + } + + /// + /// Gets the device settings for a device by key or returns null + /// + /// + /// + public object GetDebugSettingsForKey(string deviceKey) + { + return DeviceDebugSettings[deviceKey]; + } } /// @@ -114,16 +108,15 @@ namespace PepperDash.Core.Logging /// public class DebugContextItem { - /// - /// The level of debug messages to print - /// + /// + /// 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; } - } -} \ No newline at end of file + /// + /// Property to tell the program not to intitialize when it boots, if desired + /// + [JsonProperty("doNotLoadOnNextBoot")] + public bool DoNotLoadOnNextBoot { get; set; } + } \ No newline at end of file diff --git a/src/PepperDash.Core/Logging/DebugWebsocketSink.cs b/src/PepperDash.Core/Logging/DebugWebsocketSink.cs index 81d981ec..d62b3c8b 100644 --- a/src/PepperDash.Core/Logging/DebugWebsocketSink.cs +++ b/src/PepperDash.Core/Logging/DebugWebsocketSink.cs @@ -1,10 +1,6 @@ extern alias NewtonsoftJson; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Crestron.SimplSharp; using Org.BouncyCastle.Asn1.X509; using Serilog; diff --git a/src/PepperDash.Core/Network/DiscoveryThings.cs b/src/PepperDash.Core/Network/DiscoveryThings.cs index 973c03a4..c01613b7 100644 --- a/src/PepperDash.Core/Network/DiscoveryThings.cs +++ b/src/PepperDash.Core/Network/DiscoveryThings.cs @@ -4,19 +4,17 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core -{ +namespace PepperDash.Core; + +/// +/// Not in use +/// + public static class NetworkComm + { /// /// Not in use /// - public static class NetworkComm - { - /// - /// Not in use - /// static NetworkComm() { } - } - -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/PasswordManagement/Config.cs b/src/PepperDash.Core/PasswordManagement/Config.cs index 22aa4881..a5f071a4 100644 --- a/src/PepperDash.Core/PasswordManagement/Config.cs +++ b/src/PepperDash.Core/PasswordManagement/Config.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.PasswordManagement -{ +namespace PepperDash.Core.PasswordManagement; + /// /// JSON password configuration /// @@ -22,5 +22,4 @@ namespace PepperDash.Core.PasswordManagement { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/PasswordManagement/Constants.cs b/src/PepperDash.Core/PasswordManagement/Constants.cs index 65a1bf45..d4cf1e0b 100644 --- a/src/PepperDash.Core/PasswordManagement/Constants.cs +++ b/src/PepperDash.Core/PasswordManagement/Constants.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.PasswordManagement -{ +namespace PepperDash.Core.PasswordManagement; + /// /// Constants /// @@ -53,5 +53,4 @@ namespace PepperDash.Core.PasswordManagement /// Generic string value change constant /// public const ushort StringValueChange = 201; - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/PasswordManagement/PasswordClient.cs b/src/PepperDash.Core/PasswordManagement/PasswordClient.cs index 9443be0b..4a6c7368 100644 --- a/src/PepperDash.Core/PasswordManagement/PasswordClient.cs +++ b/src/PepperDash.Core/PasswordManagement/PasswordClient.cs @@ -1,10 +1,10 @@ using System; -namespace PepperDash.Core.PasswordManagement -{ - /// - /// Represents a PasswordClient - /// +namespace PepperDash.Core.PasswordManagement; + +/// +/// A class to allow user interaction with the PasswordManager +/// public class PasswordClient { /// @@ -192,5 +192,4 @@ namespace PepperDash.Core.PasswordManagement GetPasswordByIndex(args.Index); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/PasswordManagement/PasswordManager.cs b/src/PepperDash.Core/PasswordManagement/PasswordManager.cs index 9ba008e4..d08a1010 100644 --- a/src/PepperDash.Core/PasswordManagement/PasswordManager.cs +++ b/src/PepperDash.Core/PasswordManagement/PasswordManager.cs @@ -2,11 +2,11 @@ using System.Collections.Generic; using Crestron.SimplSharp; -namespace PepperDash.Core.PasswordManagement -{ - /// - /// Represents a PasswordManager - /// +namespace PepperDash.Core.PasswordManagement; + +/// +/// Allows passwords to be stored and managed +/// public class PasswordManager { /// @@ -196,7 +196,7 @@ namespace PepperDash.Core.PasswordManagement /// /// Protected ushort change event handler /// - /// + /// /// /// protected void OnUshrtChange(ushort value, ushort index, ushort type) @@ -243,5 +243,4 @@ namespace PepperDash.Core.PasswordManagement PasswordChange(this, args); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/SystemInfo/EventArgs and Constants.cs b/src/PepperDash.Core/SystemInfo/EventArgs and Constants.cs index a83f8901..e6d697f3 100644 --- a/src/PepperDash.Core/SystemInfo/EventArgs and Constants.cs +++ b/src/PepperDash.Core/SystemInfo/EventArgs and Constants.cs @@ -4,68 +4,68 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.SystemInfo -{ +namespace PepperDash.Core.SystemInfo; + /// /// Constants /// public class SystemInfoConstants { - /// - /// - /// + /// + /// + /// public const ushort BoolValueChange = 1; /// /// /// - public const ushort CompleteBoolChange = 2; + public const ushort CompleteBoolChange = 2; /// /// /// - public const ushort BusyBoolChange = 3; - - /// - /// - /// + public const ushort BusyBoolChange = 3; + + /// + /// + /// public const ushort UshortValueChange = 101; - /// - /// - /// + /// + /// + /// public const ushort StringValueChange = 201; /// /// /// - public const ushort ConsoleResponseChange = 202; + public const ushort ConsoleResponseChange = 202; /// /// /// - public const ushort ProcessorUptimeChange = 203; + public const ushort ProcessorUptimeChange = 203; /// /// /// - public const ushort ProgramUptimeChange = 204; + public const ushort ProgramUptimeChange = 204; - /// - /// - /// + /// + /// + /// public const ushort ObjectChange = 301; /// /// /// - public const ushort ProcessorConfigChange = 302; + public const ushort ProcessorConfigChange = 302; /// /// /// - public const ushort EthernetConfigChange = 303; + public const ushort EthernetConfigChange = 303; /// /// /// - public const ushort ControlSubnetConfigChange = 304; + public const ushort ControlSubnetConfigChange = 304; /// /// /// - public const ushort ProgramConfigChange = 305; + public const ushort ProgramConfigChange = 305; } /// @@ -73,18 +73,18 @@ namespace PepperDash.Core.SystemInfo /// public class ProcessorChangeEventArgs : EventArgs { - /// - /// - /// + /// + /// + /// public ProcessorInfo Processor { get; set; } /// /// /// - public ushort Type { get; set; } + public ushort Type { get; set; } /// /// /// - public ushort Index { get; set; } + public ushort Index { get; set; } /// /// Constructor @@ -119,18 +119,18 @@ namespace PepperDash.Core.SystemInfo /// public class EthernetChangeEventArgs : EventArgs { - /// - /// - /// + /// + /// + /// public EthernetInfo Adapter { get; set; } /// /// /// - public ushort Type { get; set; } + public ushort Type { get; set; } /// /// /// - public ushort Index { get; set; } + public ushort Index { get; set; } /// /// Constructor @@ -143,7 +143,7 @@ namespace PepperDash.Core.SystemInfo /// /// Constructor overload /// - /// + /// /// public EthernetChangeEventArgs(EthernetInfo ethernet, ushort type) { @@ -154,9 +154,9 @@ namespace PepperDash.Core.SystemInfo /// /// Constructor overload /// - /// + /// /// - /// + /// public EthernetChangeEventArgs(EthernetInfo ethernet, ushort type, ushort index) { Adapter = ethernet; @@ -170,18 +170,18 @@ namespace PepperDash.Core.SystemInfo /// public class ControlSubnetChangeEventArgs : EventArgs { - /// - /// - /// + /// + /// + /// public ControlSubnetInfo Adapter { get; set; } /// /// /// - public ushort Type { get; set; } + public ushort Type { get; set; } /// /// /// - public ushort Index { get; set; } + public ushort Index { get; set; } /// /// Constructor @@ -216,18 +216,18 @@ namespace PepperDash.Core.SystemInfo /// public class ProgramChangeEventArgs : EventArgs { - /// - /// - /// + /// + /// + /// public ProgramInfo Program { get; set; } /// /// /// - public ushort Type { get; set; } + public ushort Type { get; set; } /// /// /// - public ushort Index { get; set; } + public ushort Index { get; set; } /// /// Constructor @@ -240,7 +240,7 @@ namespace PepperDash.Core.SystemInfo /// /// Constructor overload /// - /// + /// /// public ProgramChangeEventArgs(ProgramInfo program, ushort type) { @@ -251,14 +251,13 @@ namespace PepperDash.Core.SystemInfo /// /// Constructor overload /// - /// + /// /// - /// + /// public ProgramChangeEventArgs(ProgramInfo program, ushort type, ushort index) { Program = program; Type = type; Index = index; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/SystemInfo/SystemInfoConfig.cs b/src/PepperDash.Core/SystemInfo/SystemInfoConfig.cs index 8dc3acaf..950abecb 100644 --- a/src/PepperDash.Core/SystemInfo/SystemInfoConfig.cs +++ b/src/PepperDash.Core/SystemInfo/SystemInfoConfig.cs @@ -4,52 +4,52 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.SystemInfo -{ +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; } /// @@ -66,45 +66,45 @@ namespace PepperDash.Core.SystemInfo /// 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; } /// @@ -121,29 +121,29 @@ namespace PepperDash.Core.SystemInfo /// 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; } /// @@ -160,37 +160,37 @@ namespace PepperDash.Core.SystemInfo /// 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; } /// @@ -200,5 +200,4 @@ namespace PepperDash.Core.SystemInfo { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/SystemInfo/SystemInfoToSimpl.cs b/src/PepperDash.Core/SystemInfo/SystemInfoToSimpl.cs index 45f787f5..00309676 100644 --- a/src/PepperDash.Core/SystemInfo/SystemInfoToSimpl.cs +++ b/src/PepperDash.Core/SystemInfo/SystemInfoToSimpl.cs @@ -4,37 +4,37 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.SystemInfo -{ +namespace PepperDash.Core.SystemInfo; + /// /// System Info class /// public class SystemInfoToSimpl { - /// - /// Notifies of bool change - /// + /// + /// Notifies of bool change + /// public event EventHandler BoolChange; - /// - /// Notifies of string change - /// + /// + /// Notifies of string change + /// public event EventHandler StringChange; - /// - /// Notifies of processor change - /// + /// + /// Notifies of processor change + /// public event EventHandler ProcessorChange; - /// - /// Notifies of ethernet change - /// + /// + /// Notifies of ethernet change + /// public event EventHandler EthernetChange; - /// - /// Notifies of control subnet change - /// + /// + /// Notifies of control subnet change + /// public event EventHandler ControlSubnetChange; - /// - /// Notifies of program change - /// + /// + /// Notifies of program change + /// public event EventHandler ProgramChange; /// @@ -336,10 +336,10 @@ namespace PepperDash.Core.SystemInfo /// /// private method to parse console messages /// - /// + /// /// - /// - /// + /// + /// /// private string ParseConsoleResponse(string data, string line, string dataStart, string dataEnd) { @@ -467,5 +467,4 @@ namespace PepperDash.Core.SystemInfo ProgramChange(this, args); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/Web/BouncyCertificate.cs b/src/PepperDash.Core/Web/BouncyCertificate.cs index 9e885094..148b6eb1 100644 --- a/src/PepperDash.Core/Web/BouncyCertificate.cs +++ b/src/PepperDash.Core/Web/BouncyCertificate.cs @@ -20,352 +20,336 @@ using Org.BouncyCastle.Crypto.Operators; using BigInteger = Org.BouncyCastle.Math.BigInteger; using X509Certificate = Org.BouncyCastle.X509.X509Certificate; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Taken From https://github.com/rlipscombe/bouncy-castle-csharp/ +/// +internal class BouncyCertificate { - /// - /// 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) { - 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; + } + + 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); + } + + 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); + } + + 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; + } + + 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 { - // We need to pass 'Exportable', otherwise we can't get the private key. - var issuerCertificate = new X509Certificate2(issuerFileName, password, X509KeyStorageFlags.Exportable); - return issuerCertificate; + var pfx = certificate.Export(X509ContentType.Pfx, CertificatePassword); + File.WriteAllBytes(string.Format("{0}.pfx", Path.Combine(outputDirectory, certName)), pfx); } - - /// - /// IssueCertificate method - /// - public X509Certificate2 IssueCertificate(string subjectName, X509Certificate2 issuerCertificate, string[] subjectAlternativeNames, KeyPurposeID[] usages) + catch (Exception ex) { - // 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); + CrestronConsole.PrintLine(string.Format("Failed to write x509 cert pfx\r\n{0}", ex.Message)); } - - /// - /// CreateCertificateAuthorityCertificate method - /// - public X509Certificate2 CreateCertificateAuthorityCertificate(string subjectName, string[] subjectAlternativeNames, KeyPurposeID[] usages) + // Create Base 64 encoded CER (public key only) + using (var writer = new StreamWriter($"{Path.Combine(outputDirectory, certName)}.cer", false)) { - // 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); + 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 pfx\r\n{0}", ex.Message)); + CrestronConsole.PrintLine(string.Format("Failed to write x509 cert cer\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; } } + 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; + } } \ No newline at end of file diff --git a/src/PepperDash.Core/Web/RequestHandlers/DefaultRequestHandler.cs b/src/PepperDash.Core/Web/RequestHandlers/DefaultRequestHandler.cs index 154dc01e..2fee0a62 100644 --- a/src/PepperDash.Core/Web/RequestHandlers/DefaultRequestHandler.cs +++ b/src/PepperDash.Core/Web/RequestHandlers/DefaultRequestHandler.cs @@ -1,10 +1,10 @@ using Crestron.SimplSharp.WebScripting; -namespace PepperDash.Core.Web.RequestHandlers -{ - /// - /// Represents a DefaultRequestHandler - /// +namespace PepperDash.Core.Web.RequestHandlers; + + /// + /// Web API default request handler + /// public class DefaultRequestHandler : WebApiBaseRequestHandler { /// @@ -13,5 +13,4 @@ namespace PepperDash.Core.Web.RequestHandlers public DefaultRequestHandler() : base(true) { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs b/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs index 927092db..e8b3e85b 100644 --- a/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs +++ b/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs @@ -3,164 +3,160 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -namespace PepperDash.Core.Web.RequestHandlers +namespace PepperDash.Core.Web.RequestHandlers; + +public abstract class WebApiBaseRequestAsyncHandler:IHttpCwsHandler { - public abstract class WebApiBaseRequestAsyncHandler:IHttpCwsHandler + private readonly Dictionary> _handlers; + protected readonly bool EnableCors; + + /// + /// Constructor + /// + protected WebApiBaseRequestAsyncHandler(bool enableCors) { - private readonly Dictionary> _handlers; - protected readonly bool EnableCors; + EnableCors = enableCors; - /// - /// Constructor - /// - protected WebApiBaseRequestAsyncHandler(bool enableCors) + _handlers = new Dictionary> { - EnableCors = enableCors; + {"CONNECT", HandleConnect}, + {"DELETE", HandleDelete}, + {"GET", HandleGet}, + {"HEAD", HandleHead}, + {"OPTIONS", HandleOptions}, + {"PATCH", HandlePatch}, + {"POST", HandlePost}, + {"PUT", HandlePut}, + {"TRACE", HandleTrace} + }; + } - _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 + /// + /// + public void ProcessRequest(HttpCwsContext context) + { + if (!_handlers.TryGetValue(context.Request.HttpMethod, out Func handler)) + { + return; } - /// - /// Constructor - /// - protected WebApiBaseRequestAsyncHandler() - : this(false) + if (EnableCors) { + context.Response.Headers.Add("Access-Control-Allow-Origin", "*"); + context.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); } - /// - /// Handles CONNECT method requests - /// - /// - protected virtual async Task HandleConnect(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } + var handlerTask = handler(context); - /// - /// 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(); - } + handlerTask.GetAwaiter().GetResult(); } } diff --git a/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs b/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs index a02f3497..0d36a863 100644 --- a/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs +++ b/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using Crestron.SimplSharp.WebScripting; -namespace PepperDash.Core.Web.RequestHandlers -{ +namespace PepperDash.Core.Web.RequestHandlers; + /// /// CWS Base Handler, implements IHttpCwsHandler /// @@ -164,5 +164,4 @@ namespace PepperDash.Core.Web.RequestHandlers handler(context); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/Web/WebApiServer.cs b/src/PepperDash.Core/Web/WebApiServer.cs index 42bc555b..4b7c1c30 100644 --- a/src/PepperDash.Core/Web/WebApiServer.cs +++ b/src/PepperDash.Core/Web/WebApiServer.cs @@ -10,8 +10,8 @@ using JsonConvert = NewtonsoftJson::Newtonsoft.Json.JsonConvert; using JObject = NewtonsoftJson::Newtonsoft.Json.Linq.JObject; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Core.Web -{ +namespace PepperDash.Core.Web; + /// /// Web API server /// @@ -286,5 +286,4 @@ namespace PepperDash.Core.Web Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception InnerException: {0}", ex.InnerException); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/WebApi/Presets/Preset.cs b/src/PepperDash.Core/WebApi/Presets/Preset.cs index 88df890c..8d174b78 100644 --- a/src/PepperDash.Core/WebApi/Presets/Preset.cs +++ b/src/PepperDash.Core/WebApi/Presets/Preset.cs @@ -1,45 +1,45 @@ using System; -namespace PepperDash.Core.WebApi.Presets -{ - /// - /// Represents a Preset - /// +namespace PepperDash.Core.WebApi.Presets; + +/// +/// Represents a preset +/// public class Preset { - /// - /// ID of preset - /// + /// + /// ID of preset + /// public int Id { get; set; } - /// - /// Gets or sets the UserId - /// + /// + /// User ID + /// public int UserId { get; set; } - /// - /// Gets or sets the RoomTypeId - /// + /// + /// Room Type ID + /// public int RoomTypeId { get; set; } - /// - /// Gets or sets the PresetName - /// + /// + /// Preset Name + /// public string PresetName { get; set; } - /// - /// Gets or sets the PresetNumber - /// + /// + /// Preset Number + /// public int PresetNumber { get; set; } - /// - /// Gets or sets the Data - /// + /// + /// Preset Data + /// public string Data { get; set; } - /// - /// Constructor - /// + /// + /// Constructor + /// public Preset() { PresetName = ""; @@ -53,35 +53,34 @@ namespace PepperDash.Core.WebApi.Presets /// 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); } } + /// + /// True when the preset is found + /// + public bool LookupSuccess { get; private set; } + + /// + /// S+ helper + /// + public ushort ULookupSuccess { get { return (ushort)(LookupSuccess ? 1 : 0); } } - /// - /// Gets or sets the Preset - /// - public Preset Preset { get; private set; } + /// + /// The preset + /// + public Preset Preset { get; private set; } /// /// For Simpl+ /// public PresetReceivedEventArgs() { } - /// - /// Constructor - /// - /// - /// + /// + /// Constructor + /// + /// + /// public PresetReceivedEventArgs(Preset preset, bool success) { - LookupSuccess = success; + LookupSuccess = success; Preset = preset; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/WebApi/Presets/User.cs b/src/PepperDash.Core/WebApi/Presets/User.cs index 4044ae7b..a20803e4 100644 --- a/src/PepperDash.Core/WebApi/Presets/User.cs +++ b/src/PepperDash.Core/WebApi/Presets/User.cs @@ -4,31 +4,31 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.WebApi.Presets -{ +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; } } @@ -38,19 +38,19 @@ namespace PepperDash.Core.WebApi.Presets /// public class UserReceivedEventArgs : EventArgs { - /// - /// True when user is found - /// - public bool LookupSuccess { get; private set; } + /// + /// 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); } } + /// + /// For stupid S+ + /// + public ushort ULookupSuccess { get { return (ushort)(LookupSuccess ? 1 : 0); } } - /// - /// Gets or sets the User - /// + /// + /// + /// public User User { get; private set; } /// @@ -58,14 +58,14 @@ namespace PepperDash.Core.WebApi.Presets /// public UserReceivedEventArgs() { } - /// - /// Constructor - /// - /// - /// + /// + /// Constructor + /// + /// + /// public UserReceivedEventArgs(User user, bool success) { - LookupSuccess = success; + LookupSuccess = success; User = user; } } @@ -75,19 +75,18 @@ namespace PepperDash.Core.WebApi.Presets /// 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; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/WebApi/Presets/WebApiPasscodeClient.cs b/src/PepperDash.Core/WebApi/Presets/WebApiPasscodeClient.cs index 831d2d02..32e63cda 100644 --- a/src/PepperDash.Core/WebApi/Presets/WebApiPasscodeClient.cs +++ b/src/PepperDash.Core/WebApi/Presets/WebApiPasscodeClient.cs @@ -10,26 +10,26 @@ using JObject = NewtonsoftJson::Newtonsoft.Json.Linq.JObject; using PepperDash.Core.JsonToSimpl; -namespace PepperDash.Core.WebApi.Presets -{ - /// - /// Passcode client for the WebApi - /// +namespace PepperDash.Core.WebApi.Presets; + +/// +/// Passcode client for the WebApi +/// public class WebApiPasscodeClient : IKeyed { - /// - /// Notifies when user received - /// + /// + /// Notifies when user received + /// public event EventHandler UserReceived; - /// - /// Notifies when Preset received - /// + /// + /// Notifies when Preset received + /// public event EventHandler PresetReceived; - /// - /// Gets or sets the Key - /// + /// + /// Unique identifier for this instance + /// public string Key { get; private set; } //string JsonMasterKey; @@ -56,13 +56,13 @@ namespace PepperDash.Core.WebApi.Presets { } - /// - /// Initializes the instance - /// - /// - /// - /// - /// + /// + /// Initializes the instance + /// + /// + /// + /// + /// public void Initialize(string key, string jsonMasterKey, string urlBase, string defaultPresetJsonFilePath) { Key = key; @@ -75,44 +75,41 @@ namespace PepperDash.Core.WebApi.Presets J2SMaster.Initialize(jsonMasterKey); } - /// - /// Gets the user for a passcode - /// - /// - /// - /// GetUserForPasscode method - /// + /// + /// Gets the user for a passcode + /// + /// 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(); + // 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) - UserReceived(this, new UserReceivedEventArgs(user, true)); - } - else - if (handler != null) - UserReceived(this, new UserReceivedEventArgs(null, false)); + 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) + UserReceived(this, new UserReceivedEventArgs(user, true)); + } + else + if (handler != null) + UserReceived(this, new UserReceivedEventArgs(null, false)); } /// @@ -138,57 +135,57 @@ namespace PepperDash.Core.WebApi.Presets PresetNumber = presetNumber }; - var handler = PresetReceived; + 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); + 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; + 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 + // 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, "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) - PresetReceived(this, new PresetReceivedEventArgs(preset, true)); - } - else // no existing preset - { - CurrentPreset = new Preset(); + //Debug.Console(1, this, "Loaded preset has no data. Loading default template."); LoadDefaultPresetData(); - if (handler != null) - PresetReceived(this, new PresetReceivedEventArgs(null, false)); + return; } + + J2SMaster.LoadWithJson(preset.Data); + if (handler != null) + PresetReceived(this, new PresetReceivedEventArgs(preset, true)); + } + else // no existing preset + { + CurrentPreset = new Preset(); + LoadDefaultPresetData(); + if (handler != null) + PresetReceived(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)); + if (handler != null) + PresetReceived(this, new PresetReceivedEventArgs(null, false)); } } @@ -247,8 +244,8 @@ namespace PepperDash.Core.WebApi.Presets { CurrentPreset.Data = json; - if (!UrlBase.StartsWith("https")) - return; + 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)); @@ -257,8 +254,8 @@ namespace PepperDash.Core.WebApi.Presets req.ContentString = JsonConvert.SerializeObject(CurrentPreset); var client = new HttpsClient(); - client.HostVerification = false; - client.PeerVerification = false; + client.HostVerification = false; + client.PeerVerification = false; try { var resp = client.Dispatch(req); @@ -281,4 +278,3 @@ namespace PepperDash.Core.WebApi.Presets } } } -} diff --git a/src/PepperDash.Core/XSigUtility/Serialization/IXSigSerialization.cs b/src/PepperDash.Core/XSigUtility/Serialization/IXSigSerialization.cs index 8303731e..b1dcae6b 100644 --- a/src/PepperDash.Core/XSigUtility/Serialization/IXSigSerialization.cs +++ b/src/PepperDash.Core/XSigUtility/Serialization/IXSigSerialization.cs @@ -1,25 +1,24 @@ using System.Collections.Generic; using PepperDash.Core.Intersystem.Tokens; -namespace PepperDash.Core.Intersystem.Serialization +namespace PepperDash.Core.Intersystem.Serialization; + +/// +/// Interface to determine XSig serialization for an object. +/// +public interface IXSigSerialization { /// - /// Interface to determine XSig serialization for an object. + /// Serialize the sig data /// - public interface IXSigSerialization - { - /// - /// Serialize the sig data - /// - /// - IEnumerable Serialize(); + /// + IEnumerable Serialize(); - /// - /// Deserialize the sig data - /// - /// - /// - /// - T Deserialize(IEnumerable tokens) where T : class, IXSigSerialization; - } + /// + /// Deserialize the sig data + /// + /// + /// + /// + T Deserialize(IEnumerable tokens) where T : class, IXSigSerialization; } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/Serialization/XSigSerializationException.cs b/src/PepperDash.Core/XSigUtility/Serialization/XSigSerializationException.cs index 8f3fc047..4db0e970 100644 --- a/src/PepperDash.Core/XSigUtility/Serialization/XSigSerializationException.cs +++ b/src/PepperDash.Core/XSigUtility/Serialization/XSigSerializationException.cs @@ -1,28 +1,27 @@ using System; -namespace PepperDash.Core.Intersystem.Serialization +namespace PepperDash.Core.Intersystem.Serialization; + +/// +/// Class to handle this specific exception type +/// +public class XSigSerializationException : Exception { /// - /// Class to handle this specific exception type + /// default constructor /// - public class XSigSerializationException : Exception - { - /// - /// default constructor - /// - public XSigSerializationException() { } + public XSigSerializationException() { } - /// - /// constructor with message - /// - /// - public XSigSerializationException(string message) : base(message) { } + /// + /// constructor with message + /// + /// + public XSigSerializationException(string message) : base(message) { } - /// - /// constructor with message and innner exception - /// - /// - /// - public XSigSerializationException(string message, Exception inner) : base(message, inner) { } - } + /// + /// constructor with message and innner exception + /// + /// + /// + public XSigSerializationException(string message, Exception inner) : base(message, inner) { } } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/Tokens/XSigAnalogToken.cs b/src/PepperDash.Core/XSigUtility/Tokens/XSigAnalogToken.cs index 68c61d90..b5cb2e68 100644 --- a/src/PepperDash.Core/XSigUtility/Tokens/XSigAnalogToken.cs +++ b/src/PepperDash.Core/XSigUtility/Tokens/XSigAnalogToken.cs @@ -1,98 +1,87 @@ using System; -namespace PepperDash.Core.Intersystem.Tokens +namespace PepperDash.Core.Intersystem.Tokens; + +/// +/// Represents an XSigAnalogToken +/// +public sealed class XSigAnalogToken : XSigToken, IFormattable { + private readonly ushort _value; + /// - /// Represents an XSigAnalogToken + /// Constructor /// - public sealed class XSigAnalogToken : XSigToken, IFormattable + /// + /// + public XSigAnalogToken(int index, ushort value) + : base(index) { - private readonly ushort _value; + // 10-bits available for analog encoded data + if (index >= 1024 || index < 0) + throw new ArgumentOutOfRangeException("index"); - /// - /// 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; + } - _value = value; - } + /// + /// + /// + public ushort Value + { + get { return _value; } + } - /// - /// - /// - public ushort Value - { - get { return _value; } - } + /// + /// + /// + public override XSigTokenType TokenType + { + get { return XSigTokenType.Analog; } + } - /// - /// - /// - 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) + }; + } - /// - /// - /// - /// - 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) - }; - } + /// + /// + /// + /// + /// + public override XSigToken GetTokenWithOffset(int offset) + { + if (offset == 0) return this; + return new XSigAnalogToken(Index + offset, Value); + } - /// - /// - /// - /// - /// - /// - /// GetTokenWithOffset method - /// - public override XSigToken GetTokenWithOffset(int offset) - { - if (offset == 0) return this; - return new XSigAnalogToken(Index + offset, Value); - } + /// + /// + /// + /// + public override string ToString() + { + return Index + " = 0x" + Value.ToString("X4"); + } - /// - /// - /// - /// - /// - /// 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); - } + /// + /// + /// + /// + /// + /// + public string ToString(string format, IFormatProvider formatProvider) + { + return Value.ToString(format, formatProvider); } } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/Tokens/XSigDigitalToken.cs b/src/PepperDash.Core/XSigUtility/Tokens/XSigDigitalToken.cs index 50fac7fc..a82d0eb2 100644 --- a/src/PepperDash.Core/XSigUtility/Tokens/XSigDigitalToken.cs +++ b/src/PepperDash.Core/XSigUtility/Tokens/XSigDigitalToken.cs @@ -1,95 +1,84 @@ using System; -namespace PepperDash.Core.Intersystem.Tokens +namespace PepperDash.Core.Intersystem.Tokens; + +/// +/// Represents an XSigDigitalToken +/// +public sealed class XSigDigitalToken : XSigToken { + private readonly bool _value; + /// - /// Represents an XSigDigitalToken + /// /// - public sealed class XSigDigitalToken : XSigToken + /// + /// + public XSigDigitalToken(int index, bool value) + : base(index) { - private readonly bool _value; + // 12-bits available for digital encoded data + if (index >= 4096 || index < 0) + throw new ArgumentOutOfRangeException("index"); - /// - /// - /// - /// - /// - 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; + } - _value = value; - } + /// + /// + /// + public bool Value + { + get { return _value; } + } - /// - /// - /// - public bool Value - { - get { return _value; } - } + /// + /// + /// + public override XSigTokenType TokenType + { + get { return XSigTokenType.Digital; } + } - /// - /// - /// - 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) + }; + } - /// - /// - /// - /// - public override byte[] GetBytes() - { - return new[] { - (byte)(0x80 | (Value ? 0 : 0x20) | ((Index - 1) >> 7)), - (byte)((Index - 1) & 0x7F) - }; - } + /// + /// + /// + /// + /// + public override XSigToken GetTokenWithOffset(int offset) + { + if (offset == 0) return this; + return new XSigDigitalToken(Index + offset, Value); + } - /// - /// - /// - /// - /// - /// - /// GetTokenWithOffset method - /// - public override XSigToken GetTokenWithOffset(int offset) - { - if (offset == 0) return this; - return new XSigDigitalToken(Index + offset, Value); - } + /// + /// + /// + /// + public override string ToString() + { + return Index + " = " + (Value ? "High" : "Low"); + } - /// - /// - /// - /// - /// - /// ToString method - /// - /// - public override string ToString() - { - return Index + " = " + (Value ? "High" : "Low"); - } - - /// - /// - /// - /// - /// - /// - /// ToString method - /// - public string ToString(IFormatProvider formatProvider) - { - return Value.ToString(formatProvider); - } + /// + /// + /// + /// + /// + public string ToString(IFormatProvider formatProvider) + { + return Value.ToString(formatProvider); } } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/Tokens/XSigSerialToken.cs b/src/PepperDash.Core/XSigUtility/Tokens/XSigSerialToken.cs index 635d40e3..3b6a3f5f 100644 --- a/src/PepperDash.Core/XSigUtility/Tokens/XSigSerialToken.cs +++ b/src/PepperDash.Core/XSigUtility/Tokens/XSigSerialToken.cs @@ -1,88 +1,80 @@ using System; using System.Text; -namespace PepperDash.Core.Intersystem.Tokens +namespace PepperDash.Core.Intersystem.Tokens; + +/// +/// Represents an XSigSerialToken +/// +public sealed class XSigSerialToken : XSigToken { + private readonly string _value; + /// - /// Represents an XSigSerialToken + /// Constructor /// - public sealed class XSigSerialToken : XSigToken + /// + /// + public XSigSerialToken(int index, string value) + : base(index) { - private readonly string _value; + // 10-bits available for serial encoded data + if (index >= 1024 || index < 0) + throw new ArgumentOutOfRangeException("index"); - /// - /// 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; + } - _value = value; - } + /// + /// + /// + public string Value + { + get { return _value; } + } - /// - /// - /// - public string Value - { - get { return _value; } - } + /// + /// + /// + public override XSigTokenType TokenType + { + get { return XSigTokenType.Serial; } + } - /// - /// - /// - 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; - /// - /// - /// - /// - 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; + } - Buffer.BlockCopy(serialBytes, 0, xsig, 2, serialBytes.Length); - return xsig; - } + /// + /// + /// + /// + /// + public override XSigToken GetTokenWithOffset(int offset) + { + if (offset == 0) return this; + return new XSigSerialToken(Index + offset, Value); + } - /// - /// - /// - /// - /// - /// - /// 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 + "\""; - } + /// + /// + /// + /// + public override string ToString() + { + return Index + " = \"" + Value + "\""; } } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/Tokens/XSigToken.cs b/src/PepperDash.Core/XSigUtility/Tokens/XSigToken.cs index 4c00a2ed..cd706bd4 100644 --- a/src/PepperDash.Core/XSigUtility/Tokens/XSigToken.cs +++ b/src/PepperDash.Core/XSigUtility/Tokens/XSigToken.cs @@ -1,45 +1,44 @@ -namespace PepperDash.Core.Intersystem.Tokens +namespace PepperDash.Core.Intersystem.Tokens; + +/// +/// Represents the base class for all XSig datatypes. +/// +public abstract class XSigToken { + private readonly int _index; + /// - /// Represents the base class for all XSig datatypes. + /// Constructs an XSigToken with the specified index. /// - public abstract class XSigToken + /// Index for the data. + protected XSigToken(int index) { - 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); + _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); } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/Tokens/XSigTokenType.cs b/src/PepperDash.Core/XSigUtility/Tokens/XSigTokenType.cs index 26d6c123..60641b4f 100644 --- a/src/PepperDash.Core/XSigUtility/Tokens/XSigTokenType.cs +++ b/src/PepperDash.Core/XSigUtility/Tokens/XSigTokenType.cs @@ -1,23 +1,22 @@ -namespace PepperDash.Core.Intersystem.Tokens +namespace PepperDash.Core.Intersystem.Tokens; + +/// +/// XSig token types. +/// +public enum XSigTokenType { /// - /// XSig token types. + /// Digital signal datatype. /// - public enum XSigTokenType - { - /// - /// Digital signal datatype. - /// - Digital, + Digital, - /// - /// Analog signal datatype. - /// - Analog, + /// + /// Analog signal datatype. + /// + Analog, - /// - /// Serial signal datatype. - /// - Serial - } + /// + /// Serial signal datatype. + /// + Serial } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/XSigHelpers.cs b/src/PepperDash.Core/XSigUtility/XSigHelpers.cs index d93cc32b..4f970be2 100644 --- a/src/PepperDash.Core/XSigUtility/XSigHelpers.cs +++ b/src/PepperDash.Core/XSigUtility/XSigHelpers.cs @@ -18,264 +18,221 @@ using PepperDash.Core.Intersystem.Tokens; 11111111 <- denotes end of data */ -namespace PepperDash.Core.Intersystem +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 { /// - /// Helper methods for creating XSig byte sequences compatible with the Intersystem Communications (ISC) symbol. + /// Forces all outputs to 0. /// - /// - /// 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 + /// Bytes in XSig format for clear outputs trigger. + public static byte[] ClearOutputs() { - /// - /// 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. + 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. + public static byte[] GetBytes(IXSigSerialization xSigSerialization, int offset) + { + var tokens = xSigSerialization.Serialize(); + if (tokens == null) return new byte[0]; + using (var memoryStream = new MemoryStream()) { - return new byte[] { 0xFC }; - } + using (var tokenWriter = new XSigTokenStreamWriter(memoryStream)) + tokenWriter.WriteXSigData(xSigSerialization, offset); - /// - /// 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; + 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. + 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. + 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. + 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. + 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. + 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. + 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. + 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. + 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. + 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. + 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. + 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. + 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; + } } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/XSigTokenStreamReader.cs b/src/PepperDash.Core/XSigUtility/XSigTokenStreamReader.cs index 03e79946..3c222960 100644 --- a/src/PepperDash.Core/XSigUtility/XSigTokenStreamReader.cs +++ b/src/PepperDash.Core/XSigUtility/XSigTokenStreamReader.cs @@ -4,153 +4,143 @@ using Crestron.SimplSharp.CrestronIO; using PepperDash.Core.Intersystem.Serialization; using PepperDash.Core.Intersystem.Tokens; -namespace PepperDash.Core.Intersystem +namespace PepperDash.Core.Intersystem; + +/// +/// XSigToken stream reader. +/// +public sealed class XSigTokenStreamReader : IDisposable { + private readonly Stream _stream; + private readonly bool _leaveOpen; + + /// /// - /// XSigToken stream reader. + /// XSigToken stream reader constructor. /// - public sealed class XSigTokenStreamReader : IDisposable + /// 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) { - private readonly Stream _stream; - private readonly bool _leaveOpen; + if (stream == null) + throw new ArgumentNullException("stream"); + if (!stream.CanRead) + throw new ArgumentException("The specified stream cannot be read from."); - /// - /// - /// XSigToken stream reader constructor. - /// - /// Input stream to read from. - /// Stream is null. - /// Stream cannot be read from. - public XSigTokenStreamReader(Stream stream) - : this(stream, false) { } + _stream = stream; + _leaveOpen = leaveOpen; + } - /// - /// 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) + /// + /// Reads a 16-bit unsigned integer from the specified stream using Big Endian byte order. + /// + /// Input stream + /// Result + /// True if successful, otherwise false. + 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. + public XSigToken ReadXSigToken() + { + ushort prefix; + if (!TryReadUInt16BE(_stream, out prefix)) + return null; + + if ((prefix & 0xF880) == 0xC800) // Serial data { - if (stream == null) - throw new ArgumentNullException("stream"); - if (!stream.CanRead) - throw new ArgumentException("The specified stream cannot be read from."); + 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; + } - _stream = stream; - _leaveOpen = leaveOpen; + return new XSigSerialToken((ushort)(index + 1), new string(chars, 0, n)); } - /// - /// 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) + if ((prefix & 0xC880) == 0xC000) // Analog data { - 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)) + ushort data; + if (!TryReadUInt16BE(_stream, out data)) 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; + 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); } - /// - /// Reads all available XSig tokens from the stream. - /// - /// XSigToken collection. - /// - /// ReadAllXSigTokens method - /// - public IEnumerable ReadAllXSigTokens() + if ((prefix & 0xC080) == 0x8000) // Digital data { - var tokens = new List(); - XSigToken token; - while ((token = ReadXSigToken()) != null) - tokens.Add(token); - - return tokens; + var index = ((prefix & 0x1F00) >> 1) | (prefix & 0x7F); + var value = (prefix & 0x2000) == 0; + return new XSigDigitalToken((ushort)(index + 1), value); } - /// - /// 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()); - } + return null; + } - /// - /// Disposes of the internal stream if specified to not leave open. - /// - public void Dispose() - { - if (!_leaveOpen) - _stream.Dispose(); - } + /// + /// Reads all available XSig tokens from the stream. + /// + /// XSigToken collection. + 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(); } } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/XSigTokenStreamWriter.cs b/src/PepperDash.Core/XSigUtility/XSigTokenStreamWriter.cs index 12eeaf91..da973acd 100644 --- a/src/PepperDash.Core/XSigUtility/XSigTokenStreamWriter.cs +++ b/src/PepperDash.Core/XSigUtility/XSigTokenStreamWriter.cs @@ -5,147 +5,131 @@ using Crestron.SimplSharp.CrestronIO; using PepperDash.Core.Intersystem.Serialization; using PepperDash.Core.Intersystem.Tokens; -namespace PepperDash.Core.Intersystem +namespace PepperDash.Core.Intersystem; + +/// +/// XSigToken stream writer. +/// +public sealed class XSigTokenStreamWriter : IDisposable { + private readonly Stream _stream; + private readonly bool _leaveOpen; + + /// /// - /// XSigToken stream writer. + /// XSigToken stream writer constructor. /// - public sealed class XSigTokenStreamWriter : IDisposable + /// 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) { - private readonly Stream _stream; - private readonly bool _leaveOpen; + if (stream == null) + throw new ArgumentNullException("stream"); + if (!stream.CanWrite) + throw new ArgumentException("The specified stream cannot be written to."); - /// - /// - /// XSigToken stream writer constructor. - /// - /// Input stream to write to. - /// Stream is null. - /// Stream cannot be written to. - public XSigTokenStreamWriter(Stream stream) - : this(stream, false) { } + _stream = stream; + _leaveOpen = leaveOpen; + } - /// - /// 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) + /// + /// Write XSig data gathered from an IXSigStateResolver to the stream. + /// + /// IXSigStateResolver object. + 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. + 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. + public void WriteXSigData(XSigToken token) + { + WriteXSigData(token, 0); + } + + /// + /// Write XSigToken to the stream. + /// + /// XSigToken object. + /// Index offset for each XSigToken. + 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. + 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) { - 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) { - foreach (var token in tokens) - { - if (token == null) continue; - var bytes = token.GetTokenWithOffset(offset).GetBytes(); - _stream.Write(bytes, 0, bytes.Length); - } + 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(); - } + /// + /// Disposes of the internal stream if specified to not leave open. + /// + public void Dispose() + { + if (!_leaveOpen) + _stream.Dispose(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs b/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs index 070f1743..4982a642 100644 --- a/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs +++ b/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs @@ -13,507 +13,408 @@ using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +/// +/// Base class for bridge API variants +/// +public abstract class BridgeApi : EssentialsDevice { - /// - /// Base class for bridge API variants - /// - [Obsolete("Will be removed in v3.0.0")] - public abstract class BridgeApi : EssentialsDevice + protected BridgeApi(string key) : + base(key) { - /// - /// Constructor - /// - /// Device key - protected BridgeApi(string key) : - base(key) - { + } +} + +/// +/// Bridge API using EISC +/// +public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor +{ + public EiscApiPropertiesConfig PropertiesConfig { get; private set; } + + public Dictionary JoinMaps { get; private set; } + + public BasicTriList Eisc { get; private set; } + + public EiscApiAdvanced(DeviceConfig dc, BasicTriList eisc) : + base(dc.Key) + { + JoinMaps = new Dictionary(); + + PropertiesConfig = dc.Properties.ToObject(); + //PropertiesConfig = JsonConvert.DeserializeObject(dc.Properties.ToString()); + + Eisc = eisc; + + Eisc.SigChange += Eisc_SigChange; + + CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, Eisc, 120000, 300000); + + AddPostActivationAction(LinkDevices); + AddPostActivationAction(LinkRooms); + AddPostActivationAction(RegisterEisc); + } + + public override bool CustomActivate() + { + CommunicationMonitor.Start(); + return base.CustomActivate(); + } + + public override bool Deactivate() + { + CommunicationMonitor.Stop(); + return base.Deactivate(); + } + + private void LinkDevices() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Linking Devices..."); + + if (PropertiesConfig.Devices == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, "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; + } + + Debug.LogMessage(LogEventLevel.Information, this, + "{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.", + device.Key); + } + } + + private void RegisterEisc() + { + if (Eisc.Registered) + { + return; + } + + var registerResult = Eisc.Register(); + + if (registerResult != eDeviceRegistrationUnRegistrationResponse.Success) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Registration result: {0}", registerResult); + return; + } + + Debug.LogMessage(LogEventLevel.Debug, this, "EISC registration successful"); + } + + public void LinkRooms() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Linking Rooms..."); + + if (PropertiesConfig.Rooms == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, "No rooms linked to this bridge."); + return; + } + + foreach (var room in PropertiesConfig.Rooms) + { + var rm = DeviceManager.GetDeviceForKey(room.RoomKey) as IBridgeAdvanced; + + if (rm == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, + "Room {0} does not implement IBridgeAdvanced. Skipping...", room.RoomKey); + continue; + } + + rm.LinkToApi(Eisc, room.JoinStart, room.JoinMapKey, this); } } /// - /// Class to link devices and rooms to an EISC Instance + /// Adds a join map /// - public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor + /// + /// + public void AddJoinMap(string deviceKey, JoinMapBaseAdvanced joinMap) { - /// - /// 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) + if (!JoinMaps.ContainsKey(deviceKey)) { - 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); + JoinMaps.Add(deviceKey, joinMap); } - - /// - /// CustomActivate method - /// - public override bool CustomActivate() + else { - CommunicationMonitor.Start(); - return base.CustomActivate(); + Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to add join map with key '{0}'. Key already exists in JoinMaps dictionary", deviceKey); } - - /// - /// 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 + /// Prints all the join maps on this bridge /// - public class EiscApiPropertiesConfig + public virtual void PrintJoinMaps() { - /// - /// Gets or sets the Control - /// - [JsonProperty("control")] - public EssentialsControlPropertiesConfig Control { get; set; } + CrestronConsole.ConsoleCommandResponse("Join Maps for EISC IPID: {0}\r\n", Eisc.ID.ToString("X")); - /// - /// 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 + foreach (var joinMap in JoinMaps) { - /// - /// 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; } + CrestronConsole.ConsoleCommandResponse("Join map for device '{0}':", joinMap.Key); + joinMap.Value.PrintJoinMapInfo(); } + } + /// + /// Generates markdown for all join maps on this bridge + /// + public virtual void MarkdownForBridge(string bridgeKey) + { + Debug.LogMessage(LogEventLevel.Information, this, "Writing Joinmaps to files for EISC IPID: {0}", Eisc.ID.ToString("X")); - /// - /// Represents a ApiRoomPropertiesConfig - /// - public class ApiRoomPropertiesConfig + foreach (var joinMap in JoinMaps) { - /// - /// 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; } + Debug.LogMessage(LogEventLevel.Information, "Generating markdown for device '{0}':", joinMap.Key); + joinMap.Value.MarkdownJoinMapInfo(joinMap.Key, bridgeKey); } - } /// - /// Factory class for EiscApiAdvanced devices + /// Prints the join map for a device by key /// - /// - /// 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 + /// + public void PrintJoinMapForDevice(string deviceKey) { - /// - /// Constructor - /// - public EiscApiAdvancedFactory() + var joinMap = JoinMaps[deviceKey]; + + if (joinMap == null) { - TypeNames = new List { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced", "eiscapiadvudp", "eiscapiadvancedudp" }; + Debug.LogMessage(LogEventLevel.Information, this, "Unable to find joinMap for device with key: '{0}'", deviceKey); + return; } - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) + Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key); + joinMap.PrintJoinMapInfo(); + } + /// + /// Prints the join map for a device by key + /// + /// + public void MarkdownJoinMapForDevice(string deviceKey, string bridgeKey) + { + var joinMap = JoinMaps[deviceKey]; + + if (joinMap == null) { - Debug.LogDebug("Attempting to create new EiscApiAdvanced Device"); + Debug.LogMessage(LogEventLevel.Information, this, "Unable to find joinMap for device with key: '{0}'", deviceKey); + return; + } - var controlProperties = CommFactory.GetControlPropertiesConfig(dc); + Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key); + joinMap.MarkdownJoinMapInfo(deviceKey, bridgeKey); + } - BasicTriList eisc; - - switch (dc.Type.ToLower()) + /// + /// Used for debugging to trigger an action based on a join number and type + /// + /// + /// + /// + public void ExecuteJoinAction(uint join, string type, object state) + { + try + { + switch (type.ToLower()) { - case "eiscapiadvudp": - case "eiscapiadvancedudp": + case "digital": { - 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)) + var uo = Eisc.BooleanOutput[join].UserObject as Action; + if (uo != null) { - Debug.LogInformation("Unable to build VC-4 EISC Client for device {deviceKey}. Room ID is missing or empty", dc.Key); - eisc = null; - break; + Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString()); + uo(Convert.ToBoolean(state)); } - eisc = new VirtualControlEISCClient(controlProperties.IpIdInt, controlProperties.RoomId, - Global.ControlSystem); + else + Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); + break; + } + case "analog": + { + var uo = Eisc.BooleanOutput[join].UserObject as Action; + if (uo != null) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString()); + uo(Convert.ToUInt16(state)); + } + else + Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); break; + } + case "serial": + { + var uo = Eisc.BooleanOutput[join].UserObject as Action; + if (uo != null) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString()); + uo(Convert.ToString(state)); + } + else + Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); break; } default: - eisc = null; - break; + { + Debug.LogMessage(LogEventLevel.Verbose, "Unknown join type. Use digital/serial/analog"); + break; + } } + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); + } - if (eisc == null) - { - return null; - } + } - return new EiscApiAdvanced(dc, eisc); + /// + /// Handles incoming sig changes + /// + /// + /// + protected void Eisc_SigChange(object currentDevice, SigEventArgs args) + { + try + { + Debug.LogMessage(LogEventLevel.Verbose, this, "EiscApiAdvanced change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); + var uo = args.Sig.UserObject; + + if (uo == null) return; + + Debug.LogMessage(LogEventLevel.Debug, this, "Executing Action: {0}", uo.ToString()); + 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); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Error in Eisc_SigChange handler: {0}", e); } } + #region Implementation of ICommunicationMonitor + + public StatusMonitorBase CommunicationMonitor { get; private set; } + + #endregion +} + +public class EiscApiPropertiesConfig +{ + [JsonProperty("control")] + public EssentialsControlPropertiesConfig Control { get; set; } + + [JsonProperty("devices")] + public List Devices { get; set; } + + [JsonProperty("rooms")] + public List Rooms { get; set; } + + + public class ApiDevicePropertiesConfig + { + [JsonProperty("deviceKey")] + public string DeviceKey { get; set; } + + [JsonProperty("joinStart")] + public uint JoinStart { get; set; } + + [JsonProperty("joinMapKey")] + public string JoinMapKey { get; set; } + } + + public class ApiRoomPropertiesConfig + { + [JsonProperty("roomKey")] + public string RoomKey { get; set; } + + [JsonProperty("joinStart")] + public uint JoinStart { get; set; } + + [JsonProperty("joinMapKey")] + public string JoinMapKey { get; set; } + } + +} + +public class EiscApiAdvancedFactory : EssentialsDeviceFactory +{ + public EiscApiAdvancedFactory() + { + TypeNames = new List { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new EiscApiAdvanced Device"); + + var controlProperties = CommFactory.GetControlPropertiesConfig(dc); + + BasicTriList eisc; + + switch (dc.Type.ToLower()) + { + 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.LogMessage(LogEventLevel.Information, "Unable to build VC-4 EISC Client for device {0}. 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); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/BridgeHelper.cs b/src/PepperDash.Essentials.Core/Bridges/BridgeHelper.cs index 8d183b77..3a3ceff2 100644 --- a/src/PepperDash.Essentials.Core/Bridges/BridgeHelper.cs +++ b/src/PepperDash.Essentials.Core/Bridges/BridgeHelper.cs @@ -3,71 +3,62 @@ using Serilog.Events; //using PepperDash.Essentials.Devices.Common.Cameras; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +/// +/// Helper methods for bridges +/// +public static class BridgeHelper { - /// - /// Helper methods for bridges - /// - public static class BridgeHelper + public static void PrintJoinMap(string command) { - /// - /// 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)) { - 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(); - } + Debug.LogMessage(LogEventLevel.Information, "Unable to find advanced bridge with key: '{0}'", bridgeKey); + return; } - /// - /// JoinmapMarkdown method - /// - public static void JoinmapMarkdown(string command) + + if (targets.Length > 1) { - var targets = command.Split(' '); + var deviceKey = targets[1].Trim(); - 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); - - } + if (string.IsNullOrEmpty(deviceKey)) return; + bridge.PrintJoinMapForDevice(deviceKey); + } + else + { + bridge.PrintJoinMaps(); } } + public static void JoinmapMarkdown(string command) + { + var targets = command.Split(' '); + var bridgeKey = targets[0].Trim(); + + var bridge = DeviceManager.GetDeviceForKey(bridgeKey) as EiscApiAdvanced; + + if (bridge == null) + { + Debug.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); + + } + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/IBridge.cs b/src/PepperDash.Essentials.Core/Bridges/IBridge.cs index 34c11171..87b4bd35 100644 --- a/src/PepperDash.Essentials.Core/Bridges/IBridge.cs +++ b/src/PepperDash.Essentials.Core/Bridges/IBridge.cs @@ -1,19 +1,11 @@ using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +/// +/// Defines a device that uses JoinMapBaseAdvanced for its join map +/// +public interface IBridgeAdvanced { - /// - /// 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); - } + void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AirMediaControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AirMediaControllerJoinMap.cs index 2bd218f6..33fca20e 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AirMediaControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AirMediaControllerJoinMap.cs @@ -1,110 +1,70 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class AirMediaControllerJoinMap : JoinMapBaseAdvanced { + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + /// - /// Represents a AirMediaControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class AirMediaControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public AirMediaControllerJoinMap(uint joinStart) + : this(joinStart, typeof(AirMediaControllerJoinMap)) { - /// - /// 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){} } + + /// + /// 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){} } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AppleTvJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AppleTvJoinMap.cs index c337f9cf..3b3eaa06 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AppleTvJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AppleTvJoinMap.cs @@ -1,77 +1,52 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class AppleTvJoinMap : JoinMapBaseAdvanced { + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [JoinName("Menu")] + public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "AppleTv Menu", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Select")] + public JoinDataComplete Select = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "AppleTv Select", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + /// - /// Represents a AppleTvJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class AppleTvJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public AppleTvJoinMap(uint joinStart) + : base(joinStart, typeof(AppleTvJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/C2nRthsControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/C2nRthsControllerJoinMap.cs index bb9da22f..17f8f4db 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/C2nRthsControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/C2nRthsControllerJoinMap.cs @@ -1,63 +1,44 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class C2nRthsControllerJoinMap : JoinMapBaseAdvanced { + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + /// - /// Represents a C2nRthsControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class C2nRthsControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public C2nRthsControllerJoinMap(uint joinStart) + : this(joinStart, typeof(C2nRthsControllerJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CameraControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CameraControllerJoinMap.cs index aad43513..0cb011fa 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CameraControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CameraControllerJoinMap.cs @@ -1,140 +1,68 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +/// +/// Join map for CameraBase devices +/// +public class CameraControllerJoinMap : JoinMapBaseAdvanced { + [JoinName("TiltUp")] + public JoinDataComplete TiltUp = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Tilt Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("TiltDown")] + public JoinDataComplete TiltDown = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Tilt Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PanLeft")] + public JoinDataComplete PanLeft = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Pan Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PanRight")] + public JoinDataComplete PanRight = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Pan Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ZoomIn")] + public JoinDataComplete ZoomIn = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Zoom In", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ZoomOut")] + public JoinDataComplete ZoomOut = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Zoom Out", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata { Description = "Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PowerOn")] + public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PowerOff")] + public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "Power Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + [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 }); + [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 }); + [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 }); + + [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 }); + [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 }); + [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 }); + + [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 }); + [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 }); + [JoinName("SupportsPresets")] + public JoinDataComplete SupportsPresets = new JoinDataComplete(new JoinData { JoinNumber = 57, JoinSpan = 1 }, new JoinMetadata { Description = "Supports Presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + /// - /// Represents a CameraControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class CameraControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public CameraControllerJoinMap(uint joinStart) + : this(joinStart, typeof(CameraControllerJoinMap)) { - /// - /// 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){} } + + /// + /// 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){} } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs index b52c5309..b585916b 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs @@ -1,320 +1,196 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class CenOdtOccupancySensorBaseJoinMap : JoinMapBaseAdvanced { + #region Digitals + + [JoinName("Online")] + public JoinDataComplete Online = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ForceOccupied")] + public JoinDataComplete ForceOccupied = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Force Occupied", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ForceVacant")] + public JoinDataComplete ForceVacant = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Force Vacant", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [JoinName("AndWhenVacated")] + public JoinDataComplete AndWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, + new JoinMetadata { Description = "AndWhenVacated", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [JoinName("EnablePir")] + public JoinDataComplete EnablePir = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata { Description = "Enable Pir", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DisablePir")] + public JoinDataComplete DisablePir = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, + new JoinMetadata { Description = "Disable Pir", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 + + [JoinName("Timeout")] + public JoinDataComplete Timeout = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Timeout", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + #endregion + /// - /// Represents a CenOdtOccupancySensorBaseJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class CenOdtOccupancySensorBaseJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public CenOdtOccupancySensorBaseJoinMap(uint joinStart) + : this(joinStart, typeof(CenOdtOccupancySensorBaseJoinMap)) { - #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) - { - } } + /// + /// 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) + { + } } diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DisplayControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DisplayControllerJoinMap.cs index 3741f951..2ab95b8e 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DisplayControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DisplayControllerJoinMap.cs @@ -1,133 +1,84 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DisplayControllerJoinMap : JoinMapBaseAdvanced { + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("PowerOff")] + public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Power Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PowerOn")] + public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [JoinName("VolumeUp")] + public JoinDataComplete VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Volume Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VolumeLevel")] + public JoinDataComplete VolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Volume Level", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("VolumeDown")] + public JoinDataComplete VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "Volume Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VolumeMute")] + public JoinDataComplete VolumeMute = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "Volume Mute", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [JoinName("InputSelectOffset")] + public JoinDataComplete InputSelectOffset = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 10 }, + new JoinMetadata { Description = "Input Select", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [JoinName("InputSelect")] + public JoinDataComplete InputSelect = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Input Select", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [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 }); + + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, + new JoinMetadata { Description = "Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + /// - /// Represents a DisplayControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class DisplayControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public DisplayControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DisplayControllerJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmBladeChassisControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmBladeChassisControllerJoinMap.cs index c6488bba..3edd1222 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmBladeChassisControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmBladeChassisControllerJoinMap.cs @@ -1,113 +1,73 @@ using System; -namespace PepperDash.Essentials.Core.Bridges { +namespace PepperDash.Essentials.Core.Bridges; +public class DmBladeChassisControllerJoinMap : JoinMapBaseAdvanced { + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + /// - /// Represents a DmBladeChassisControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - 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) - { - } - + /// 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) + { + } + } diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmChassisControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmChassisControllerJoinMap.cs index 9d2217cc..db3701b3 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmChassisControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmChassisControllerJoinMap.cs @@ -1,259 +1,169 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DmChassisControllerJoinMap : JoinMapBaseAdvanced { + [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 + }); + + [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 + }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 + }); + + [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 + }); + [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 + }); + [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 + }); + + [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 }); + + [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 }); + + [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 }); + /// - /// Represents a DmChassisControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class DmChassisControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public DmChassisControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmChassisControllerJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmRmcControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmRmcControllerJoinMap.cs index 6f0df102..4ddb9ff4 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmRmcControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmRmcControllerJoinMap.cs @@ -1,143 +1,91 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DmRmcControllerJoinMap : JoinMapBaseAdvanced { + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [JoinName("Port2HdcpState")] + public JoinDataComplete Port2HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Port 2 (HDMI) HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [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 }); + + [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 }); + + + /// - /// Represents a DmRmcControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class DmRmcControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public DmRmcControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmRmcControllerJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmTxControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmTxControllerJoinMap.cs index ab1299d1..8fb99f33 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmTxControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmTxControllerJoinMap.cs @@ -1,150 +1,95 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DmTxControllerJoinMap : JoinMapBaseAdvanced { + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + + /// - /// Represents a DmTxControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class DmTxControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public DmTxControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmTxControllerJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsAudioOutputControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsAudioOutputControllerJoinMap.cs index ca1d60b4..9ad04691 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsAudioOutputControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsAudioOutputControllerJoinMap.cs @@ -1,288 +1,173 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DmpsAudioOutputControllerJoinMap : JoinMapBaseAdvanced { + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + /// - /// Represents a DmpsAudioOutputControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class DmpsAudioOutputControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public DmpsAudioOutputControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmpsAudioOutputControllerJoinMap)) { + } - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsMicrophoneControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsMicrophoneControllerJoinMap.cs index 3fba12e5..90efc964 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsMicrophoneControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsMicrophoneControllerJoinMap.cs @@ -1,72 +1,49 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DmpsMicrophoneControllerJoinMap : JoinMapBaseAdvanced { + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + /// - /// Represents a DmpsMicrophoneControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class DmpsMicrophoneControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public DmpsMicrophoneControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmpsMicrophoneControllerJoinMap)) { + } - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsRoutingControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsRoutingControllerJoinMap.cs index 8e9a3e97..e39e38c6 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsRoutingControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsRoutingControllerJoinMap.cs @@ -1,185 +1,122 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DmpsRoutingControllerJoinMap : JoinMapBaseAdvanced { + [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 }); + + [JoinName("SystemPowerOn")] + public JoinDataComplete SystemPowerOn = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "DMPS System Power On Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SystemPowerOff")] + public JoinDataComplete SystemPowerOff = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "DMPS System Power Off Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [JoinName("InputVideoNames")] + public JoinDataComplete InputVideoNames = + new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, + new JoinMetadata + { + Description = "Video Input Name", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [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 + }); + [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 + }); + [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 + }); + + [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 }); + + [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 }); + + [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 }); + /// - /// Represents a DmpsRoutingControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class DmpsRoutingControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public DmpsRoutingControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmpsRoutingControllerJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericIrControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericIrControllerJoinMap.cs index 57977737..00087187 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericIrControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericIrControllerJoinMap.cs @@ -1,10 +1,7 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Bridges.JoinMaps -{ - /// - /// Represents a GenericIrControllerJoinMap - /// +namespace PepperDash.Essentials.Core.Bridges.JoinMaps; + public sealed class GenericIrControllerJoinMap : JoinMapBaseAdvanced { /// @@ -995,5 +992,4 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps : base(joinStart, typeof(GenericIrControllerJoinMap)) { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericLightingJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericLightingJoinMap.cs index 2b684d9f..179b4124 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericLightingJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericLightingJoinMap.cs @@ -1,67 +1,48 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class GenericLightingJoinMap : JoinMapBaseAdvanced { + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + + /// - /// Represents a GenericLightingJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class GenericLightingJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public GenericLightingJoinMap(uint joinStart) + : this(joinStart, typeof(GenericLightingJoinMap)) { + } - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericRelayControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericRelayControllerJoinMap.cs index 470dc4e1..03aaf041 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericRelayControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericRelayControllerJoinMap.cs @@ -1,37 +1,30 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class GenericRelayControllerJoinMap : JoinMapBaseAdvanced { + + [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 }); + /// - /// Represents a GenericRelayControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class GenericRelayControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public GenericRelayControllerJoinMap(uint joinStart) + : this(joinStart, typeof(GenericRelayControllerJoinMap)) { + } - /// - /// 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) - { - - } + /// + /// 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) + { + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsOccupancySensorBaseJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsOccupancySensorBaseJoinMap.cs index 23341e7e..228cb4f0 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsOccupancySensorBaseJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsOccupancySensorBaseJoinMap.cs @@ -1,304 +1,184 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class GlsOccupancySensorBaseJoinMap : JoinMapBaseAdvanced { + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + /// - /// Represents a GlsOccupancySensorBaseJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class GlsOccupancySensorBaseJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public GlsOccupancySensorBaseJoinMap(uint joinStart) + : this(joinStart, typeof(GlsOccupancySensorBaseJoinMap)) { - /// - /// 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) - { - } - } -} + + /// + /// 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) + { + } + +} + diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs index 98c491dd..7515c8c2 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs @@ -1,183 +1,156 @@ using System; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Bridges.JoinMaps +namespace PepperDash.Essentials.Core.Bridges.JoinMaps; + +public class GlsPartitionSensorJoinMap : JoinMapBaseAdvanced { + + #region Digital + + [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 + }); + + + [JoinName("Enable")] + public JoinDataComplete Enable = new JoinDataComplete( + new JoinData + { + JoinNumber = 2, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Sensor Enable", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [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 + }); + + [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 + }); + + [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 + }); + + [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 + + [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 + + [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 + + /// - /// Represents a GlsPartitionSensorJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class GlsPartitionSensorJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public GlsPartitionSensorJoinMap(uint joinStart) + : this(joinStart, typeof(GlsPartitionSensorJoinMap)) { - #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 - }); + /// + /// 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) + { - /// - /// 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) - { - - } } } diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdNxM4kEControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdNxM4kEControllerJoinMap.cs index 950e3f1e..43ed25c9 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdNxM4kEControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdNxM4kEControllerJoinMap.cs @@ -1,99 +1,65 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class HdMdNxM4kEControllerJoinMap : JoinMapBaseAdvanced { + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Onlne", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + /// - /// Represents a HdMdNxM4kEControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class HdMdNxM4kEControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public HdMdNxM4kEControllerJoinMap(uint joinStart) + : this(joinStart, typeof(HdMdNxM4kEControllerJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdxxxCEControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdxxxCEControllerJoinMap.cs index 2730a0ea..32bc5651 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdxxxCEControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdxxxCEControllerJoinMap.cs @@ -1,114 +1,75 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class HdMdxxxCEControllerJoinMap : JoinMapBaseAdvanced { + + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + /// - /// Represents a HdMdxxxCEControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class HdMdxxxCEControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public HdMdxxxCEControllerJoinMap(uint joinStart) + : this(joinStart, typeof(HdMdxxxCEControllerJoinMap)) { + } - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdPsXxxControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdPsXxxControllerJoinMap.cs index aee3c2f1..e5225ac6 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdPsXxxControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdPsXxxControllerJoinMap.cs @@ -1,11 +1,8 @@ using System; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Bridges -{ - /// - /// Represents a HdPsXxxControllerJoinMap - /// +namespace PepperDash.Essentials.Core.Bridges; + public class HdPsXxxControllerJoinMap : JoinMapBaseAdvanced { @@ -212,5 +209,4 @@ namespace PepperDash.Essentials.Core.Bridges : base(joinStart, type) { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/Hrxxx0WirelessRemoteControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/Hrxxx0WirelessRemoteControllerJoinMap.cs index 5c4c858e..ca9ef3c6 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/Hrxxx0WirelessRemoteControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/Hrxxx0WirelessRemoteControllerJoinMap.cs @@ -1,414 +1,245 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class Hrxxx0WirelessRemoteControllerJoinMap : JoinMapBaseAdvanced { + [JoinName("Power")] + public JoinDataComplete Power = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Power", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Menu")] + public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Menu", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Guide")] + public JoinDataComplete Guide = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Guide", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Info")] + public JoinDataComplete Info = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Info", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VolumeUp")] + public JoinDataComplete VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "VolumeUp", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VolumeDown")] + public JoinDataComplete VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "VolumeDown", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DialPadUp")] + public JoinDataComplete DialPadUp = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "DialPadUp", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DialPadDown")] + public JoinDataComplete DialPadDown = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "DialPadDown", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DialPadLeft")] + public JoinDataComplete DialPadLeft = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, + new JoinMetadata { Description = "DialPadLeft", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DialPadRight")] + public JoinDataComplete DialPadRight = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, + new JoinMetadata { Description = "DialPadRight", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DialPadSelect")] + public JoinDataComplete DialPadSelect = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "DialPadSelect", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChannelUp")] + public JoinDataComplete ChannelUp = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "ChannelUp", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChannelDown")] + public JoinDataComplete ChannelDown = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "ChannelDown", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Mute")] + public JoinDataComplete Mute = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, + new JoinMetadata { Description = "Mute", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Exit")] + public JoinDataComplete Exit = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, + new JoinMetadata { Description = "Exit", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Last")] + public JoinDataComplete Last = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, + new JoinMetadata { Description = "Last", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Play")] + public JoinDataComplete Play = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, + new JoinMetadata { Description = "Play", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Pause")] + public JoinDataComplete Pause = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, + new JoinMetadata { Description = "Pause", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Rewind")] + public JoinDataComplete Rewind = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, + new JoinMetadata { Description = "Rewind", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("FastForward")] + public JoinDataComplete FastForward = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, + new JoinMetadata { Description = "FastForward", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PreviousTrack")] + public JoinDataComplete PreviousTrack = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata { Description = "PreviousTrack", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("NextTrack")] + public JoinDataComplete NextTrack = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, + new JoinMetadata { Description = "NextTrack", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Stop")] + public JoinDataComplete Stop = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, + new JoinMetadata { Description = "Stop", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Record")] + public JoinDataComplete Record = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, + new JoinMetadata { Description = "Record", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Dvr")] + public JoinDataComplete Dvr = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, + new JoinMetadata { Description = "Dvr", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad1")] + public JoinDataComplete Keypad1 = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad2Abc")] + public JoinDataComplete Keypad2 = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad2Abc", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad3Def")] + public JoinDataComplete Keypad3Def = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad3Def", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad4Ghi")] + public JoinDataComplete Keypad4Ghi = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad4Ghi", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad5Jkl")] + public JoinDataComplete Keypad5Jkl = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad5Jkl", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad6Mno")] + public JoinDataComplete Keypad6Mno = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad6Mno", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad7Pqrs")] + public JoinDataComplete Keypad7Pqrs = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad7Pqrs", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad8Tuv")] + public JoinDataComplete Keypad8Tuv = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad8Tuv", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad9Wxyz")] + public JoinDataComplete Keypad9Wxyz = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad9Wxyz", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad0")] + public JoinDataComplete Keypad0 = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad0", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Clear")] + public JoinDataComplete Clear = new JoinDataComplete(new JoinData { JoinNumber = 36, JoinSpan = 1 }, + new JoinMetadata { Description = "Clear", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Enter")] + public JoinDataComplete Enter = new JoinDataComplete(new JoinData { JoinNumber = 37, JoinSpan = 1 }, + new JoinMetadata { Description = "Enter", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Red")] + public JoinDataComplete Red = new JoinDataComplete(new JoinData { JoinNumber = 38, JoinSpan = 1 }, + new JoinMetadata { Description = "Red", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Green")] + public JoinDataComplete Green = new JoinDataComplete(new JoinData { JoinNumber = 39, JoinSpan = 1 }, + new JoinMetadata { Description = "Green", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Yellow")] + public JoinDataComplete Yellow = new JoinDataComplete(new JoinData { JoinNumber = 40, JoinSpan = 1 }, + new JoinMetadata { Description = "Yellow", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Blue")] + public JoinDataComplete Blue = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, + new JoinMetadata { Description = "Blue", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom1")] + public JoinDataComplete Custom1 = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom2")] + public JoinDataComplete Custom2 = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom3")] + public JoinDataComplete Custom3 = new JoinDataComplete(new JoinData { JoinNumber = 44, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom3", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom4")] + public JoinDataComplete Custom4 = new JoinDataComplete(new JoinData { JoinNumber = 45, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom4", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom5")] + public JoinDataComplete Custom5 = new JoinDataComplete(new JoinData { JoinNumber = 46, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom5", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom6")] + public JoinDataComplete Custom6 = new JoinDataComplete(new JoinData { JoinNumber = 47, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom6", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom7")] + public JoinDataComplete Custom7 = new JoinDataComplete(new JoinData { JoinNumber = 48, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom7", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom8")] + public JoinDataComplete Custom8 = new JoinDataComplete(new JoinData { JoinNumber = 49, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom8", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom9")] + public JoinDataComplete Custom9 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom9", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Fav")] + public JoinDataComplete Fav = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1 }, + new JoinMetadata { Description = "Fav", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Home")] + public JoinDataComplete Home = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1 }, + new JoinMetadata { Description = "Home", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("BatteryLow")] + public JoinDataComplete BatteryLow = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1 }, + new JoinMetadata { Description = "BatteryLow", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("BatteryCritical")] + public JoinDataComplete BatteryCritical = new JoinDataComplete(new JoinData { JoinNumber = 54, JoinSpan = 1 }, + new JoinMetadata { Description = "BatteryCritical", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("BatteryVoltage")] + public JoinDataComplete BatteryVoltage = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "BatteryVoltage", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + /// - /// Represents a Hrxxx0WirelessRemoteControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class Hrxxx0WirelessRemoteControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public Hrxxx0WirelessRemoteControllerJoinMap(uint joinStart) + : this(joinStart, typeof(Hrxxx0WirelessRemoteControllerJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IAnalogInputJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IAnalogInputJoinMap.cs index 59f90347..80509ecc 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IAnalogInputJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IAnalogInputJoinMap.cs @@ -1,44 +1,33 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class IAnalogInputJoinMap : JoinMapBaseAdvanced { + + [JoinName("InputValue")] + public JoinDataComplete InputValue = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Input Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + [JoinName("MinimumChange")] + public JoinDataComplete MinimumChange = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Minimum voltage change required to reflect a change", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + /// - /// Represents a IAnalogInputJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class IAnalogInputJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public IAnalogInputJoinMap(uint joinStart) + : this(joinStart, typeof(IAnalogInputJoinMap)) { + } - /// - /// 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) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected IAnalogInputJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IBasicCommunicationJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IBasicCommunicationJoinMap.cs index b4c473cb..1db5b1ff 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IBasicCommunicationJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IBasicCommunicationJoinMap.cs @@ -1,71 +1,49 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class IBasicCommunicationJoinMap : JoinMapBaseAdvanced { + [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 }); + + [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 }); + + [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 }); + + [JoinName("Connect")] + public JoinDataComplete Connect = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Connect", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Connected")] + public JoinDataComplete Connected = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Connected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Status")] + public JoinDataComplete Status = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + /// - /// Represents a IBasicCommunicationJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class IBasicCommunicationJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public IBasicCommunicationJoinMap(uint joinStart) + : this(joinStart, typeof(IBasicCommunicationJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalInputJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalInputJoinMap.cs index 0f77fce3..ceed325d 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalInputJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalInputJoinMap.cs @@ -1,36 +1,30 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class IDigitalInputJoinMap : JoinMapBaseAdvanced { + + [JoinName("InputState")] + public JoinDataComplete InputState = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Input State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + /// - /// Represents a IDigitalInputJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class IDigitalInputJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public IDigitalInputJoinMap(uint joinStart) + : this(joinStart, typeof(IDigitalInputJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalOutputJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalOutputJoinMap.cs index 05895acb..8abb2b74 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalOutputJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalOutputJoinMap.cs @@ -1,36 +1,30 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class IDigitalOutputJoinMap : JoinMapBaseAdvanced { + + [JoinName("OutputState")] + public JoinDataComplete OutputState = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Get / Set state of Digital Input", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + /// - /// Represents a IDigitalOutputJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class IDigitalOutputJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public IDigitalOutputJoinMap(uint joinStart) + : this(joinStart, typeof(IDigitalOutputJoinMap)) { - /// - /// 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) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected IDigitalOutputJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IRBlurayBaseJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IRBlurayBaseJoinMap.cs index 3e66eda6..d63a1f52 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IRBlurayBaseJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IRBlurayBaseJoinMap.cs @@ -4,359 +4,218 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +/// +/// Join map for IRBlurayBase devices +/// +public class IRBlurayBaseJoinMap : JoinMapBaseAdvanced { - /// - /// Join map for IRBlurayBase devices + [JoinName("PowerOn")] + public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Power On", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PowerOff")] + public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Power Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PowerToggle")] + public JoinDataComplete PowerToggle = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Power Toggle", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Up")] + public JoinDataComplete Up = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Nav Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Down")] + public JoinDataComplete Down = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Nav Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Left")] + public JoinDataComplete Left = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "Nav Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Right")] + public JoinDataComplete Right = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "Nav Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Select")] + public JoinDataComplete Select = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "Select", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Menu")] + public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, + new JoinMetadata { Description = "Menu", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Exit")] + public JoinDataComplete Exit = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, + new JoinMetadata { Description = "Exit", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit0")] + public JoinDataComplete Digit0 = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 0", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit1")] + public JoinDataComplete Digit1 = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 1", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit2")] + public JoinDataComplete Digit2 = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 2", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit3")] + public JoinDataComplete Digit3 = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 3", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit4")] + public JoinDataComplete Digit4 = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 4", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit5")] + public JoinDataComplete Digit5 = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 5", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit6")] + public JoinDataComplete Digit6 = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 6", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit7")] + public JoinDataComplete Digit7 = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 7", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit8")] + public JoinDataComplete Digit8 = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 8", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit9")] + public JoinDataComplete Digit9 = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 9", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("KeypadClear")] + public JoinDataComplete KeypadClear = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad Clear", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("KeypadEnter")] + public JoinDataComplete KeypadEnter = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad Enter", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [JoinName("LastChannel")] + public JoinDataComplete LastChannel = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, + new JoinMetadata { Description = "Last Channel", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Guide")] + public JoinDataComplete Guide = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, + new JoinMetadata { Description = "Guide", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Info")] + public JoinDataComplete Info = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, + new JoinMetadata { Description = "Info", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Red")] + public JoinDataComplete Red = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, + new JoinMetadata { Description = "Red", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Green")] + public JoinDataComplete Green = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, + new JoinMetadata { Description = "Green", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Yellow")] + public JoinDataComplete Yellow = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, + new JoinMetadata { Description = "Yellow", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Blue")] + public JoinDataComplete Blue = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, + new JoinMetadata { Description = "Blue", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + + [JoinName("Play")] + public JoinDataComplete Play = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, + new JoinMetadata { Description = "Play", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Pause")] + public JoinDataComplete Pause = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, + new JoinMetadata { Description = "Pause", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Stop")] + public JoinDataComplete Stop = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, + new JoinMetadata { Description = "Stop", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("FFwd")] + public JoinDataComplete FFwd = new JoinDataComplete(new JoinData { JoinNumber = 36, JoinSpan = 1 }, + new JoinMetadata { Description = "FFwd", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Rewind")] + public JoinDataComplete Rewind = new JoinDataComplete(new JoinData { JoinNumber = 37, JoinSpan = 1 }, + new JoinMetadata { Description = "Rewind", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChapPlus")] + public JoinDataComplete ChapPlus = new JoinDataComplete(new JoinData { JoinNumber = 38, JoinSpan = 1 }, + new JoinMetadata { Description = "Chapter Plus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChapMinus")] + public JoinDataComplete ChapMinus = new JoinDataComplete(new JoinData { JoinNumber = 39, JoinSpan = 1 }, + new JoinMetadata { Description = "Chapter Minus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Replay")] + public JoinDataComplete Replay = new JoinDataComplete(new JoinData { JoinNumber = 40, JoinSpan = 1 }, + new JoinMetadata { Description = "Replay", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Record")] + public JoinDataComplete Record = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, + new JoinMetadata { Description = "Record", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 /// - public class IRBlurayBaseJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public IRBlurayBaseJoinMap(uint joinStart) + : this(joinStart, typeof(IRBlurayBaseJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/PduJoinMapBase.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/PduJoinMapBase.cs index f52b96c4..10bf590d 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/PduJoinMapBase.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/PduJoinMapBase.cs @@ -1,87 +1,59 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class PduJoinMapBase : JoinMapBaseAdvanced { + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "PDU Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("Online")] + public JoinDataComplete Online = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [JoinName("OutletName")] + public JoinDataComplete OutletName = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Outlet Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("OutletEnabled")] + public JoinDataComplete OutletEnabled = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Outlet Enabled", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [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 }); + + + /// - /// Represents a PduJoinMapBase + /// Constructor to use when instantiating this Join Map without inheriting from it /// - 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 }); + /// Join this join map will start at + public PduJoinMapBase(uint joinStart) + :base(joinStart, typeof(PduJoinMapBase)) + { + } - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SetTopBoxControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SetTopBoxControllerJoinMap.cs index ce9a4290..0705eb93 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SetTopBoxControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SetTopBoxControllerJoinMap.cs @@ -1,402 +1,239 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class SetTopBoxControllerJoinMap : JoinMapBaseAdvanced { + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [JoinName("Select")] + public JoinDataComplete Select = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Select", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Menu")] + public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Menu", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Exit")] + public JoinDataComplete Exit = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Exit", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [JoinName("Dash")] + public JoinDataComplete Dash = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Dash", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [JoinName("Guide")] + public JoinDataComplete Guide = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Guide", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Info")] + public JoinDataComplete Info = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Info", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Red")] + public JoinDataComplete Red = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Red", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Green")] + public JoinDataComplete Green = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Green", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Yellow")] + public JoinDataComplete Yellow = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Yellow", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Blue")] + public JoinDataComplete Blue = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Blue", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [JoinName("DvrList")] + public JoinDataComplete DvrList = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, + new JoinMetadata { Description = "STB DvrList", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Play")] + public JoinDataComplete Play = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Play", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Pause")] + public JoinDataComplete Pause = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Pause", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Stop")] + public JoinDataComplete Stop = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Stop", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("FFwd")] + public JoinDataComplete FFwd = new JoinDataComplete(new JoinData { JoinNumber = 36, JoinSpan = 1 }, + new JoinMetadata { Description = "STB FFwd", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Rewind")] + public JoinDataComplete Rewind = new JoinDataComplete(new JoinData { JoinNumber = 37, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Rewind", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [JoinName("Replay")] + public JoinDataComplete Replay = new JoinDataComplete(new JoinData { JoinNumber = 40, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Replay", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Record")] + public JoinDataComplete Record = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Record", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + /// - /// Represents a SetTopBoxControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class SetTopBoxControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public SetTopBoxControllerJoinMap(uint joinStart) + : this(joinStart, typeof(SetTopBoxControllerJoinMap)) { - /// - /// 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/StatusSignControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/StatusSignControllerJoinMap.cs index 79ada2c8..98cd9218 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/StatusSignControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/StatusSignControllerJoinMap.cs @@ -1,86 +1,58 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class StatusSignControllerJoinMap : JoinMapBaseAdvanced { + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + + [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 }); + /// - /// Represents a StatusSignControllerJoinMap + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class StatusSignControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public StatusSignControllerJoinMap(uint joinStart) + : this(joinStart, typeof(StatusSignControllerJoinMap)) { - /// - /// 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) - { - } - } + + /// + /// 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) + { + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SystemMonitorJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SystemMonitorJoinMap.cs index c53c9fe6..3d9ac81b 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SystemMonitorJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SystemMonitorJoinMap.cs @@ -1,235 +1,136 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class SystemMonitorJoinMap : JoinMapBaseAdvanced { - /// - /// 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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 }); + [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 @@ -260,23 +161,22 @@ namespace PepperDash.Essentials.Core.Bridges 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 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) - { - } + /// + /// 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) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index 2a7a46c2..b691bbdb 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -1,10 +1,7 @@ using System; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Bridges.JoinMaps -{ - /// - /// Represents a VideoCodecControllerJoinMap - /// +namespace PepperDash.Essentials.Core.Bridges.JoinMaps; + public class VideoCodecControllerJoinMap : JoinMapBaseAdvanced { #region Digital @@ -26,27 +23,21 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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")] + [JoinName("Dtmf1")] public JoinDataComplete Dtmf1 = new JoinDataComplete( new JoinData { @@ -60,10 +51,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// DTMF 2 - /// - [JoinName("Dtmf2")] + [JoinName("Dtmf2")] public JoinDataComplete Dtmf2 = new JoinDataComplete( new JoinData { @@ -77,10 +65,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// DTMF 3 - /// - [JoinName("Dtmf3")] + [JoinName("Dtmf3")] public JoinDataComplete Dtmf3 = new JoinDataComplete( new JoinData { @@ -94,10 +79,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// DTMF 4 - /// - [JoinName("Dtmf4")] + [JoinName("Dtmf4")] public JoinDataComplete Dtmf4 = new JoinDataComplete( new JoinData { @@ -111,10 +93,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// DTMF 5 - /// - [JoinName("Dtmf5")] + [JoinName("Dtmf5")] public JoinDataComplete Dtmf5 = new JoinDataComplete( new JoinData { @@ -128,10 +107,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// DTMF 6 - /// - [JoinName("Dtmf6")] + [JoinName("Dtmf6")] public JoinDataComplete Dtmf6 = new JoinDataComplete( new JoinData { @@ -145,10 +121,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// DTMF 7 - /// - [JoinName("Dtmf7")] + [JoinName("Dtmf7")] public JoinDataComplete Dtmf7 = new JoinDataComplete( new JoinData { @@ -162,10 +135,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// DTMF 8 - /// - [JoinName("Dtmf8")] + [JoinName("Dtmf8")] public JoinDataComplete Dtmf8 = new JoinDataComplete( new JoinData { @@ -179,10 +149,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// DTMF 9 - /// - [JoinName("Dtmf9")] + [JoinName("Dtmf9")] public JoinDataComplete Dtmf9 = new JoinDataComplete( new JoinData { @@ -196,10 +163,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// DTMF 0 - /// - [JoinName("Dtmf0")] + [JoinName("Dtmf0")] public JoinDataComplete Dtmf0 = new JoinDataComplete( new JoinData { @@ -213,10 +177,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// DTMF * - /// - [JoinName("DtmfStar")] + [JoinName("DtmfStar")] public JoinDataComplete DtmfStar = new JoinDataComplete( new JoinData { @@ -230,10 +191,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// DTMF # - /// - [JoinName("DtmfPound")] + [JoinName("DtmfPound")] public JoinDataComplete DtmfPound = new JoinDataComplete( new JoinData { @@ -247,10 +205,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// End All Calls - /// - [JoinName("EndAllCalls")] + [JoinName("EndAllCalls")] public JoinDataComplete EndAllCalls = new JoinDataComplete( new JoinData { @@ -366,10 +321,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// Dial Phone - /// - [JoinName("DialPhone")] + [JoinName("DialPhone")] public JoinDataComplete DialPhone = new JoinDataComplete( new JoinData { @@ -400,10 +352,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// Hang Up Phone - /// - [JoinName("HangUpPhone")] + [JoinName("HangUpPhone")] public JoinDataComplete HangUpPhone = new JoinDataComplete( new JoinData { @@ -417,56 +366,47 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 - }); + [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 - }); + [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 @@ -604,56 +544,47 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 - }); + [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 - }); + [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 @@ -757,56 +688,47 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 - }); + [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 - }); + [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 @@ -961,10 +883,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - /// - /// Dial Meeting Start - /// - [JoinName("DialMeetingStart")] + [JoinName("DialMeetingStart")] public JoinDataComplete DialMeetingStart = new JoinDataComplete( new JoinData { @@ -1114,39 +1033,33 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 - }); + [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 @@ -1233,141 +1146,117 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 - }); + [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 - }); + [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 - }); + [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 - }); + [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( + [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 - }); + 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( + [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 - }); + 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( + [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 - }); + new JoinMetadata + { + Description = "Toggles the participant's pin status", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); #endregion @@ -1376,58 +1265,49 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps #region Analog - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + [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 + }); - /// - /// 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 - }); + [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 + }); - /// - /// 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 - }); + [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 @@ -1463,22 +1343,19 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 @@ -1514,56 +1391,48 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 + }); - /// - /// 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 - }); + [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 + }); + + [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 + }); /// @@ -1583,22 +1452,19 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 @@ -1651,56 +1517,47 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 - }); + [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 - }); + [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 @@ -1725,10 +1582,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); - /// - /// Phone Dial String - /// - [JoinName("PhoneDialString")] + [JoinName("PhoneDialString")] public JoinDataComplete PhoneDialString = new JoinDataComplete( new JoinData { @@ -1742,10 +1596,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); - /// - /// Current Call Data - /// - [JoinName("CurrentCallData")] + [JoinName("CurrentCallData")] public JoinDataComplete CurrentCallData = new JoinDataComplete( new JoinData { @@ -1861,22 +1712,19 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 @@ -1895,10 +1743,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); - /// - /// Current Layout String - /// - [JoinName("CurrentLayoutStringFb")] + [JoinName("CurrentLayoutStringFb")] public JoinDataComplete CurrentLayoutStringFb = new JoinDataComplete( new JoinData { @@ -1912,39 +1757,33 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 - }); + [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 + }); /// @@ -1964,90 +1803,75 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 - }); + [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 - }); + [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 - }); + [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 - }); + [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 @@ -2083,90 +1907,75 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 - }); + [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 - }); + [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 - }); + [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 - }); + [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 - }); + [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 @@ -2241,4 +2050,3 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps { } } -} diff --git a/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs b/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs index 298bbc9b..0c053d6b 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs @@ -10,156 +10,116 @@ using Crestron.SimplSharpPro.DM; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + public class CecPortController : Device, IBasicCommunicationWithStreamDebugging { - /// - /// Represents a CecPortController - /// - public class CecPortController : Device, IBasicCommunicationWithStreamDebugging + public CommunicationStreamDebugging StreamDebugging { get; private set; } + + public event EventHandler BytesReceived; + public event EventHandler TextReceived; + + public bool IsConnected { get { return true; } } + + ICec Port; + + public CecPortController(string key, Func postActivationFunc, + EssentialsControlPropertiesConfig config):base(key) { - /// - /// Gets or sets the StreamDebugging - /// - public CommunicationStreamDebugging StreamDebugging { get; private set; } + StreamDebugging = new CommunicationStreamDebugging(key); - /// - /// 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) + AddPostActivationAction(() => { - StreamDebugging = new CommunicationStreamDebugging(key); + Port = postActivationFunc(config); - AddPostActivationAction(() => - { - Port = postActivationFunc(config); + Port.StreamCec.CecChange += StreamCec_CecChange; + }); + } - Port.StreamCec.CecChange += StreamCec_CecChange; - }); + 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); + if (StreamDebugging.RxStreamDebuggingIsEnabled) + Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", ComTextHelper.GetEscapedText(bytes)); + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + } + var textHandler = TextReceived; + if (textHandler != null) + { + if (StreamDebugging.RxStreamDebuggingIsEnabled) + Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", s); + textHandler(this, new GenericCommMethodReceiveTextArgs(s)); + } + } + + #region IBasicCommunication Members + + public void SendText(string text) + { + if (Port == null) + return; + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} characters of text: '{1}'", text.Length, text); + Port.StreamCec.Send.StringValue = text; + } + + public void SendBytes(byte[] bytes) + { + if (Port == null) + return; + var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + Port.StreamCec.Send.StringValue = text; + } + + public void Connect() + { + } + + public void Disconnect() + { + } + + #endregion + + /// + /// + /// + /// + 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); } - /// - /// 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()); - } + OnDataReceived(b.ToString()); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs b/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs index ec679fae..a4407e01 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs @@ -9,17 +9,11 @@ using PepperDash.Core.Logging; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ - /// - /// Represents a ComPortController - /// +namespace PepperDash.Essentials.Core; + public class ComPortController : Device, IBasicCommunicationWithStreamDebugging { - /// - /// Gets or sets the StreamDebugging - /// - public CommunicationStreamDebugging StreamDebugging { get; private set; } + public CommunicationStreamDebugging StreamDebugging { get; private set; } /// /// Event fired when bytes are received @@ -39,27 +33,20 @@ namespace PepperDash.Essentials.Core ComPort Port; ComPort.ComPortSpec Spec; - /// - /// Constructor - /// - /// - /// - /// - /// - public ComPortController(string key, Func postActivationFunc, - ComPort.ComPortSpec spec, EssentialsControlPropertiesConfig config) : base(key) - { - StreamDebugging = new CommunicationStreamDebugging(key); + public ComPortController(string key, Func postActivationFunc, + ComPort.ComPortSpec spec, EssentialsControlPropertiesConfig config) : base(key) + { + StreamDebugging = new CommunicationStreamDebugging(key); Spec = spec; - AddPostActivationAction(() => - { - Port = postActivationFunc(config); + AddPostActivationAction(() => + { + Port = postActivationFunc(config); - RegisterAndConfigureComPort(); - }); - } + RegisterAndConfigureComPort(); + }); + } /// /// Constructor @@ -83,13 +70,22 @@ namespace PepperDash.Essentials.Core RegisterAndConfigureComPort(); } - private void RegisterAndConfigureComPort() - { - if (Port == null) - { - this.LogInformation($"Configured {Port.Parent.GetType().Name}-comport-{Port.ID} for {Key} does not exist."); - return; - } + private void RegisterAndConfigureComPort() + { + if (Port == null) + { + Debug.LogMessage(LogEventLevel.Information, this, "Configured com Port for this device does not exist."); + return; + } + if (Port.Parent is CrestronControlSystem) + { + var result = Port.Register(); + if (result != eDeviceRegistrationUnRegistrationResponse.Success) + { + Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Cannot register Com port: {0}", result); + return; // false + } + } if (Port.Parent is CrestronControlSystem || Port.Parent is CenIoCom102) @@ -124,31 +120,33 @@ namespace PepperDash.Essentials.Core void Port_SerialDataReceived(ComPort ReceivingComPort, ComPortSerialDataEventArgs args) { - OnDataReceived(args.SerialData); + OnDataReceived(args.SerialData); } - void OnDataReceived(string s) - { + 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)); + var bytesHandler = BytesReceived; + if (bytesHandler != null) + { + var bytes = Encoding.GetEncoding(28591).GetBytes(s); + if (StreamDebugging.RxStreamDebuggingIsEnabled) + Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", ComTextHelper.GetEscapedText(bytes)); + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); eventSubscribed = true; - } - var textHandler = TextReceived; - if (textHandler != null) - { - this.PrintReceivedText(s); - textHandler(this, new GenericCommMethodReceiveTextArgs(s)); + } + var textHandler = TextReceived; + if (textHandler != null) + { + if (StreamDebugging.RxStreamDebuggingIsEnabled) + Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", s); + textHandler(this, new GenericCommMethodReceiveTextArgs(s)); eventSubscribed = true; - } + } - if (!eventSubscribed) Debug.LogMessage(LogEventLevel.Warning, this, "Received data but no handler is registered"); - } + if(!eventSubscribed) Debug.LogMessage(LogEventLevel.Warning, this, "Received data but no handler is registered"); + } /// /// Deactivate method @@ -169,8 +167,9 @@ namespace PepperDash.Essentials.Core if (Port == null) return; - this.PrintSentText(text); - Port.Send(text); + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} characters of text: '{1}'", text.Length, text); + Port.Send(text); } /// @@ -181,7 +180,8 @@ namespace PepperDash.Essentials.Core if (Port == null) return; var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - this.PrintSentBytes(bytes); + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); Port.Send(text); } @@ -202,27 +202,23 @@ namespace PepperDash.Essentials.Core #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); - } + /// + /// + /// + /// + 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()); - } + OnDataReceived(b.ToString()); + } } -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs b/src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs index 11e2bc74..6ef2f916 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs @@ -13,119 +13,89 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; -namespace PepperDash.Essentials.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 { - /// - /// 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 + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - /// - /// 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?)) { - 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(); + var newSer = new JsonSerializer(); + newSer.Converters.Add(new ComSpecPropsJsonConverter()); + newSer.ObjectCreationHandling = ObjectCreationHandling.Replace; + return newSer.Deserialize(reader); } + return null; } /// - /// Represents a ComSpecPropsJsonConverter + /// /// - public class ComSpecPropsJsonConverter : JsonConverter + public override bool CanConvert(Type objectType) { - /// - 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(); - } + return objectType == typeof(ComPort.ComPortSpec?); } + public override bool CanRead { get { return true; } } + /// + /// This converter will not be used for writing + /// + public override bool CanWrite { get { return false; } } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } +} + +/// +/// The gist of this converter: The comspec JSON comes in with normal values that need to be converted +/// into enum names. This converter takes the value and applies the appropriate enum's name prefix to the value +/// and then returns the enum value using Enum.Parse. NOTE: Does not write +/// +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); + } + + public override bool CanRead { get { return true; } } + + 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; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs b/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs index 9318e04b..c6a10622 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs @@ -8,8 +8,8 @@ using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -59,43 +59,35 @@ namespace PepperDash.Essentials.Core 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.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.Ssh: + { + var ssh = new GenericSshClient(deviceConfig.Key + "-ssh", c.Address, c.Port, c.Username, c.Password); + ssh.AutoReconnect = c.AutoReconnect; + 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); + tcp.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.Telnet: break; case eControlMethod.SecureTcpIp: @@ -138,19 +130,16 @@ namespace PepperDash.Essentials.Core 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); + /// + /// Gets an ICec port from a RoutingInput or RoutingOutput on a device + /// + /// + /// + 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" @@ -196,7 +185,7 @@ namespace PepperDash.Essentials.Core config.ControlPortDevKey, config.ControlPortName); return null; - } + } /// /// Helper to grab the IComPorts device for this PortDeviceKey. Key "controlSystem" will @@ -222,86 +211,65 @@ namespace PepperDash.Essentials.Core } } - /// - /// 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; } +/// +/// +/// +public class EssentialsControlPropertiesConfig : + ControlPropertiesConfig +{ - /// - /// Gets or sets the CresnetId - /// - [JsonProperty("cresnetId", NullValueHandling = NullValueHandling.Ignore)] - public string CresnetId { get; set; } + [JsonProperty("comParams", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(ComSpecJsonConverter))] + public ComPort.ComPortSpec? ComParams { 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)); - } - } - } + [JsonProperty("cresnetId", NullValueHandling = NullValueHandling.Ignore)] + public string CresnetId { get; set; } - /// - /// Gets or sets the InfinetId - /// - [JsonProperty("infinetId", NullValueHandling = NullValueHandling.Ignore)] - public string InfinetId { 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)); + } + } + } - /// - /// 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)); - } - } - } - } + [JsonProperty("infinetId", NullValueHandling = NullValueHandling.Ignore)] + public string InfinetId { get; set; } - /// - /// 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; } - } + /// + /// 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)); + } + } + } +} + +public class IrControlSpec +{ + public string PortDeviceKey { get; set; } + public uint PortNumber { get; set; } + public string File { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/CommunicationExtras.cs b/src/PepperDash.Essentials.Core/Comm and IR/CommunicationExtras.cs index d9bd0974..cc188fa7 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/CommunicationExtras.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/CommunicationExtras.cs @@ -13,8 +13,8 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -24,5 +24,4 @@ namespace PepperDash.Essentials.Core /// Gets the Device /// IComPorts Device { get; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/ConsoleCommMockDevice.cs b/src/PepperDash.Essentials.Core/Comm and IR/ConsoleCommMockDevice.cs index 7c2af905..3f7f3097 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/ConsoleCommMockDevice.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/ConsoleCommMockDevice.cs @@ -9,11 +9,8 @@ using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ - /// - /// Represents a ConsoleCommMockDevice - /// +namespace PepperDash.Essentials.Core; + public class ConsoleCommMockDevice : EssentialsDevice, ICommunicationMonitor { /// @@ -103,31 +100,19 @@ namespace PepperDash.Essentials.Core } } - /// - /// Represents a ConsoleCommMockDeviceFactory - /// - public class ConsoleCommMockDeviceFactory : EssentialsDeviceFactory +public class ConsoleCommMockDeviceFactory : EssentialsDeviceFactory +{ + public ConsoleCommMockDeviceFactory() { - /// - /// 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); - } + TypeNames = new List() { "commmock" }; } + 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); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/GenericComm.cs b/src/PepperDash.Essentials.Core/Comm and IR/GenericComm.cs index 069244c3..6e913968 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/GenericComm.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/GenericComm.cs @@ -13,164 +13,132 @@ using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core +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 { - /// - /// 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; + + public IBasicCommunication CommPort { get; private set; } + + public GenericComm(DeviceConfig config) + : base(config) { - EssentialsControlPropertiesConfig PropertiesConfig; - /// - /// Gets the CommPort - /// - public IBasicCommunication CommPort { get; private set; } + PropertiesConfig = CommFactory.GetControlPropertiesConfig(config); - /// - /// Constructor - /// - /// the config of the device - public GenericComm(DeviceConfig config) - : base(config) + var commPort = CommFactory.CreateCommForDevice(config); + + //Fixing decision to require '-comPorts' in delcaration for DGE in order to get a device with comports included + if (commPort == null) { - - 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; - + config.Key = config.Key + "-comPorts"; + commPort = CommFactory.CreateCommForDevice(config); } - /// - /// BuildDevice method - /// - public static IKeyed BuildDevice(DeviceConfig dc) + CommPort = commPort; + + } + + public static IKeyed BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); + return new GenericComm(dc); + } + + public void SetPortConfig(string portConfig) + { + // TODO: Deserialize new EssentialsControlPropertiesConfig and handle as necessary + try { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); - return new GenericComm(dc); + PropertiesConfig = JsonConvert.DeserializeObject + (portConfig); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Error deserializing port config: {0}", e); + } + } + + protected override void CustomSetConfig(DeviceConfig config) + { + PropertiesConfig = CommFactory.GetControlPropertiesConfig(config); + + ConfigWriter.UpdateDeviceConfig(config); + } + + 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."); } - /// - /// SetPortConfig method - /// - public void SetPortConfig(string portConfig) + if (CommPort == null) { - // 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); - } + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. CommPort is null", Key); + return; } - /// - /// CustomSetConfig method - /// - /// the new device configuration - protected override void CustomSetConfig(DeviceConfig config) + 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) => { - PropertiesConfig = CommFactory.GetControlPropertiesConfig(config); + trilist.SetString(joinMap.TextReceived.JoinNumber, a.Text); + }; + trilist.SetStringSigAction(joinMap.SendText.JoinNumber, s => CommPort.SendText(s)); + trilist.SetStringSigAction(joinMap.SetPortConfig.JoinNumber, SetPortConfig); - ConfigWriter.UpdateDeviceConfig(config); - } - /// - /// LinkToApi method - /// - /// - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + var sComm = CommPort as ISocketStatus; + if (sComm == null) return; + sComm.ConnectionChange += (s, a) => { - var joinMap = new IBasicCommunicationJoinMap(joinStart); + trilist.SetUshort(joinMap.Status.JoinNumber, (ushort)(a.Client.ClientStatus)); + trilist.SetBool(joinMap.Connected.JoinNumber, a.Client.ClientStatus == + SocketStatus.SOCKET_STATUS_CONNECTED); + }; - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(joinMapSerialized); - - if (bridge != null) + trilist.SetBoolSigAction(joinMap.Connect.JoinNumber, b => + { + if (b) { - bridge.AddJoinMap(Key, joinMap); + sComm.Connect(); } else { - Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); + sComm.Disconnect(); } + }); + } +} - 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(); - } - }); - } +public class GenericCommFactory : EssentialsDeviceFactory +{ + public GenericCommFactory() + { + TypeNames = new List() { "genericComm" }; } - /// - /// Represents a GenericCommFactory - /// - public class GenericCommFactory : EssentialsDeviceFactory + public override EssentialsDevice BuildDevice(DeviceConfig dc) { - /// - /// 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); - } + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); + return new GenericComm(dc); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs b/src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs index e02027b3..d1c3a7c8 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs @@ -2,13 +2,9 @@ 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")] +namespace PepperDash.Essentials.Core; + +[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; @@ -27,13 +23,13 @@ namespace PepperDash.Essentials.Core public GenericHttpClient(string key, string name, string hostname) : base(key, name) { - Client = new HttpClient - { - HostName = hostname - }; + Client = new HttpClient + { + HostName = hostname + }; - } + } /// /// SendText method @@ -87,8 +83,8 @@ namespace PepperDash.Essentials.Core if (responseReceived.ContentString.Length > 0) { - ResponseRecived?.Invoke(this, new GenericHttpClientEventArgs(responseReceived.ContentString, (request as HttpClientRequest).Url.ToString(), error)); - } + ResponseRecived?.Invoke(this, new GenericHttpClientEventArgs(responseReceived.ContentString, (request as HttpClientRequest).Url.ToString(), error)); + } } } @@ -180,5 +176,4 @@ namespace PepperDash.Essentials.Core RequestPath = request; Error = error; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/IRPortHelper.cs b/src/PepperDash.Essentials.Core/Comm and IR/IRPortHelper.cs index 6ca4b533..b4d4069d 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/IRPortHelper.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/IRPortHelper.cs @@ -12,8 +12,8 @@ using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Helper class for IR port operations /// @@ -145,7 +145,7 @@ namespace PepperDash.Essentials.Core var port = irDev.IROutputPorts[portNum]; - + return port; } @@ -157,82 +157,82 @@ namespace PepperDash.Essentials.Core /// IrOutputPortController object public static IrOutputPortController GetIrOutputPortController(DeviceConfig config) { - Debug.LogMessage(LogEventLevel.Debug, "Attempting to create new Ir Port Controller"); + Debug.LogMessage(LogEventLevel.Debug, "Attempting to create new Ir Port Controller"); if (config == null) { return null; } - var postActivationFunc = new Func (GetIrOutputPort); + var postActivationFunc = new Func (GetIrOutputPort); var irDevice = new IrOutputPortController(config.Key + "-ir", postActivationFunc, config); return irDevice; } /* - /// - /// GetIrOutputPortController method - /// - public static IrOutputPortController GetIrOutputPortController(DeviceConfig devConf) + /// + /// Returns a ready-to-go IrOutputPortController from a DeviceConfig object. + /// + public static IrOutputPortController GetIrOutputPortController(DeviceConfig devConf) + { + var irControllerKey = devConf.Key + "-ir"; + if (devConf.Properties == null) { - 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, ""); - } + 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 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; + 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 (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 (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 (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 (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; - } - }*/ + 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; + } + }*/ } /// @@ -265,5 +265,4 @@ namespace PepperDash.Essentials.Core { FileName = ""; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/AudioControlPointListItem.cs b/src/PepperDash.Essentials.Core/Config/AudioControlPointListItem.cs index 54cc3574..3a3e2fc8 100644 --- a/src/PepperDash.Essentials.Core/Config/AudioControlPointListItem.cs +++ b/src/PepperDash.Essentials.Core/Config/AudioControlPointListItem.cs @@ -6,24 +6,14 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.Config +namespace PepperDash.Essentials.Core.Config; + +public class AudioControlPointListItem { - /// - /// Represents a AudioControlPointListItem - /// - public class AudioControlPointListItem - { - /// - /// Level controls for this audio control point - /// - [JsonProperty("levelControls")] - public Dictionary LevelControls { get; set; } = new Dictionary(); + [JsonProperty("levelControls")] + public Dictionary LevelControls { get; set; } = new Dictionary(); - /// - /// Presets for this audio control point - /// - [JsonProperty("presets")] - public Dictionary Presets { get; set; } = new Dictionary(); + [JsonProperty("presets")] + public Dictionary Presets { get; set; } = new Dictionary(); - } } diff --git a/src/PepperDash.Essentials.Core/Config/BasicConfig.cs b/src/PepperDash.Essentials.Core/Config/BasicConfig.cs index 435d448f..2e499ed4 100644 --- a/src/PepperDash.Essentials.Core/Config/BasicConfig.cs +++ b/src/PepperDash.Essentials.Core/Config/BasicConfig.cs @@ -7,8 +7,8 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core.Devices; -namespace PepperDash.Essentials.Core.Config -{ +namespace PepperDash.Essentials.Core.Config; + /// /// Override this and splice on specific room type behavior, as well as other properties /// @@ -32,50 +32,32 @@ namespace PepperDash.Essentials.Core.Config [JsonProperty("sourceLists")] public Dictionary> SourceLists { get; set; } - /// - /// Gets or sets the DestinationLists - /// - [JsonProperty("destinationLists")] - public Dictionary> DestinationLists { get; set; } + [JsonProperty("destinationLists")] + public Dictionary> DestinationLists { get; set; } - /// - /// Gets or sets the AudioControlPointLists - /// - [JsonProperty("audioControlPointLists")] - public Dictionary AudioControlPointLists { get; set; } + [JsonProperty("audioControlPointLists")] + public Dictionary AudioControlPointLists { get; set; } - /// - /// Gets or sets the CameraLists - /// - [JsonProperty("cameraLists")] - public Dictionary> CameraLists { get; set; } + [JsonProperty("cameraLists")] + public Dictionary> CameraLists { get; set; } - /// - /// Gets or sets the TieLines - /// - [JsonProperty("tieLines")] - public List TieLines { get; set; } + [JsonProperty("tieLines")] + public List TieLines { get; set; } - /// - /// Gets or sets the JoinMaps - /// - [JsonProperty("joinMaps")] - public Dictionary JoinMaps { get; set; } + [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(); - } + 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 @@ -88,11 +70,11 @@ namespace PepperDash.Essentials.Core.Config return SourceLists[key]; } - /// - /// Retrieves a DestinationListItem based on the key - /// - /// key of the list to retrieve - /// DestinationList if the key exists, null otherwise + /// + /// 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)) @@ -103,51 +85,47 @@ namespace PepperDash.Essentials.Core.Config 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) + /// + /// Retrieves a AudioControlPointList based on the key + /// + /// key of the list to retrieve + /// AudioControlPointList if the key exists, null otherwise + 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 + /// + 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 { - 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; - } + return null; } + } } -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/ConfigPropertiesHelpers.cs b/src/PepperDash.Essentials.Core/Config/ConfigPropertiesHelpers.cs index 99633266..9eb8e61d 100644 --- a/src/PepperDash.Essentials.Core/Config/ConfigPropertiesHelpers.cs +++ b/src/PepperDash.Essentials.Core/Config/ConfigPropertiesHelpers.cs @@ -9,27 +9,23 @@ using PepperDash.Essentials.Core; using PepperDash.Core; using Newtonsoft.Json.Linq; -namespace PepperDash.Essentials.Core.Config +namespace PepperDash.Essentials.Core.Config; + +public class ConfigPropertiesHelpers { /// - /// Represents a ConfigPropertiesHelpers + /// Returns the value of properties.hasAudio, or false if not defined /// - public class ConfigPropertiesHelpers + public static bool GetHasAudio(DeviceConfig deviceConfig) { - /// - /// GetHasAudio method - /// - public static bool GetHasAudio(DeviceConfig deviceConfig) - { - return deviceConfig.Properties.Value("hasAudio"); - } + 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"); - } + /// + /// Returns the value of properties.hasControls, or false if not defined + /// + public static bool GetHasControls(DeviceConfig deviceConfig) + { + return deviceConfig.Properties.Value("hasControls"); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/DeviceConfig.cs b/src/PepperDash.Essentials.Core/Config/DeviceConfig.cs index b8620bb9..49994abc 100644 --- a/src/PepperDash.Essentials.Core/Config/DeviceConfig.cs +++ b/src/PepperDash.Essentials.Core/Config/DeviceConfig.cs @@ -11,116 +11,71 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Config +namespace PepperDash.Essentials.Core.Config; + +public class DeviceConfig { - /// - /// Represents a DeviceConfig - /// - 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; } + + public DeviceConfig(DeviceConfig dc) { - /// - /// Gets or sets the Key - /// - [JsonProperty("key")] - public string Key { get; set; } + Key = dc.Key; + Uid = dc.Uid; + Name = dc.Name; + Group = dc.Group; + Type = dc.Type; - /// - /// Gets or sets the Uid - /// - [JsonProperty("uid")] - public int Uid { get; set; } + Properties = JToken.Parse(dc.Properties.ToString()); - /// - /// 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() { } + //Properties = JToken.FromObject(dc.Properties); } - /// - /// Represents a DevicePropertiesConverter - /// - public class DevicePropertiesConverter : JsonConverter + public DeviceConfig() {} +} + +/// +/// +/// +public class DevicePropertiesConverter : JsonConverter +{ + + public override bool CanConvert(Type objectType) { + return objectType == typeof(JToken); + } - /// - /// CanConvert method - /// - public override bool CanConvert(Type objectType) - { - return objectType == typeof(JToken); - } + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + return JToken.ReadFrom(reader); + } - /// - /// 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) + public override bool CanWrite + { + get { - return JToken.ReadFrom(reader); + return false; } + } - /// - 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"); - } + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException("SOD OFF HOSER"); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/Essentials/ConfigReader.cs b/src/PepperDash.Essentials.Core/Config/Essentials/ConfigReader.cs index 40c6c0cf..071e5a20 100644 --- a/src/PepperDash.Essentials.Core/Config/Essentials/ConfigReader.cs +++ b/src/PepperDash.Essentials.Core/Config/Essentials/ConfigReader.cs @@ -11,8 +11,8 @@ using PepperDash.Core; using PepperDash.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core.Config -{ +namespace PepperDash.Essentials.Core.Config; + /// /// Loads the ConfigObject from the file /// @@ -22,7 +22,7 @@ namespace PepperDash.Essentials.Core.Config /// Local Config Present Message /// public const string LocalConfigPresent = - @" + @" *************************************************** ************* Using Local config file ************* ***************************************************"; @@ -40,88 +40,92 @@ namespace PepperDash.Essentials.Core.Config 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; + // Check for local config file first + var filePath = Global.FilePathPrefix + ConfigWriter.LocalConfigFolder + Global.DirectorySeparator + Global.ConfigFileName; - bool localConfigFound = false; + bool localConfigFound = false; - Debug.LogMessage(LogEventLevel.Information, "Attempting to load Local config file: '{0}'", filePath); + Debug.LogMessage(LogEventLevel.Information, "Attempting to load Local config file: '{0}'", filePath); - // Check for local config directory first + // Check for local config directory first - var configFiles = GetConfigFiles(filePath); + 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 Local Configuration files present. Please ensure only a single file exists and reset program.****"); + "****Error: Multiple Portal Configuration files present. Please ensure only a single file exists and reset program.****"); return false; } - if(configFiles.Length == 1) + else if (configFiles.Length == 1) { - localConfigFound = true; - + 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, - "Local Configuration file not present.", filePath); - + "ERROR: Portal Configuration file not present. Please load file and reset program."); + return false; } + } - // Check for Portal Config - if(!localConfigFound) - { - filePath = Global.FilePathPrefix + Global.ConfigFileName; + // Get the actual file path + filePath = configFiles[0].FullName; - 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. + // Generate debug statement if using a local file. if (localConfigFound) { - GetLocalFileMessage(filePath); + GetLocalFileMessage(filePath); } - // Read the file - using (StreamReader fs = new StreamReader(filePath)) + // Read the file + using (StreamReader fs = new StreamReader(filePath)) + { + Debug.LogMessage(LogEventLevel.Information, "Loading config file: '{0}'", filePath); + + if (localConfigFound) { - Debug.LogMessage(LogEventLevel.Information, "Loading config file: '{0}'", filePath); + ConfigObject = JObject.Parse(fs.ReadToEnd()).ToObject(); if (localConfigFound) { @@ -166,114 +170,135 @@ namespace PepperDash.Essentials.Core.Config return true; } + else + { + var doubleObj = JObject.Parse(fs.ReadToEnd()); + ConfigObject = PortalConfigReader.MergeConfigs(doubleObj).ToObject(); + + // Extract SystemUrl and TemplateUrl into final config output + + if (doubleObj["system_url"] != null) + { + ConfigObject.SystemUrl = doubleObj["system_url"].Value(); + } + + if (doubleObj["template_url"] != null) + { + ConfigObject.TemplateUrl = doubleObj["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); + 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) + /// + /// Returns all the files from the directory specified. + /// + /// + /// + public static FileInfo[] GetConfigFiles(string filePath) + { + // Get the directory + var dir = Path.GetDirectoryName(filePath); + + if (Directory.Exists(dir)) { - // Get the directory - var dir = Path.GetDirectoryName(filePath); + Debug.LogMessage(LogEventLevel.Debug, "Searching in Directory '{0}'", dir); + // Get the directory info + var dirInfo = new DirectoryInfo(dir); - 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 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; - } + // 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; - } + /// + /// + 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; + 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; + 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 + // Line 1 .Append(new string('*', debugStringWidth)) .Append(CrestronEnvironment.NewLine) - // Line 2 + // Line 2 .Append(new string('*', debugStringWidth)) .Append(CrestronEnvironment.NewLine) - // Line 3 + // Line 3 .Append(new string('*', 2)) .Append(new string(' ', debugStringWidth - 4)) .Append(new string('*', 2)) .Append(CrestronEnvironment.NewLine) - // Line 4 + // 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 + // 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 + // Line 6 .Append(new string('*', 2)) .Append(new string(' ', debugStringWidth - 4)) .Append(new string('*', 2)) .Append(CrestronEnvironment.NewLine) - // Line 7 + // Line 7 .Append(new string('*', debugStringWidth)) .Append(CrestronEnvironment.NewLine) - // Line 8 + // Line 8 .Append(new string('*', debugStringWidth)); - Debug.LogMessage(LogEventLevel.Verbose, "Found Local config file: '{0}'", filePath); - Debug.LogMessage(LogEventLevel.Information, newDebugString.ToString()); + Debug.LogMessage(LogEventLevel.Verbose, "Found Local config file: '{0}'", filePath); + Debug.LogMessage(LogEventLevel.Information, newDebugString.ToString()); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/Essentials/ConfigUpdater.cs b/src/PepperDash.Essentials.Core/Config/Essentials/ConfigUpdater.cs index 9df673bf..a41c43e0 100644 --- a/src/PepperDash.Essentials.Core/Config/Essentials/ConfigUpdater.cs +++ b/src/PepperDash.Essentials.Core/Config/Essentials/ConfigUpdater.cs @@ -14,204 +14,194 @@ using Crestron.SimplSharpPro.Diagnostics; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Config +namespace PepperDash.Essentials.Core.Config; + +public static class ConfigUpdater { - /// - /// ConfigUpdater class - /// - public static class ConfigUpdater + public static event EventHandler ConfigStatusChanged; + + public static void GetConfigFromServer(string url) { - /// - /// ConfigStatusChanged event - /// - public static event EventHandler ConfigStatusChanged; + Debug.LogMessage(LogEventLevel.Information, "Attempting to get new config from '{0}'", url); - /// - /// GetConfigFromServer method - /// - /// URL of the config server - public static void GetConfigFromServer(string url) + // HTTP GET + var req = new HttpClientRequest(); + + try { - Debug.LogMessage(LogEventLevel.Information, "Attempting to get new config from '{0}'", url); + req.RequestType = RequestType.Get; + req.Url.Parse(url); - // HTTP GET - var req = new HttpClientRequest(); - - try - { - req.RequestType = RequestType.Get; - req.Url.Parse(url); - - new HttpClient().DispatchAsync(req, (r, e) => + new HttpClient().DispatchAsync(req, (r, e) => + { + if (e == HTTP_CALLBACK_ERROR.COMPLETED) { - if (e == HTTP_CALLBACK_ERROR.COMPLETED) + if (r.Code == 200) { - if (r.Code == 200) - { - var newConfig = r.ContentString; + var newConfig = r.ContentString; - OnStatusUpdate(eUpdateStatus.ConfigFileReceived); + OnStatusUpdate(eUpdateStatus.ConfigFileReceived); - ArchiveExistingPortalConfigs(); + ArchiveExistingPortalConfigs(); - CheckForLocalConfigAndDelete(); + CheckForLocalConfigAndDelete(); - WriteConfigToFile(newConfig); + 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); - } + RestartProgram(); } 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(); + { + Debug.LogMessage(LogEventLevel.Information, "Config Update Process Stopped. Failed to get config file from server: {0}", r.Code); + OnStatusUpdate(eUpdateStatus.UpdateFailed); + } } - } - - } - - // 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); - } + else + Debug.LogMessage(LogEventLevel.Information, "Request for config from Server Failed: {0}", e); + }); } - - /// - /// Checks for LocalConfig folder in file system and deletes if found - /// - static void CheckForLocalConfigAndDelete() + catch (Exception e) { - 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); + 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 /// @@ -258,23 +248,12 @@ namespace PepperDash.Essentials.Core.Config UpdateFailed } - /// - /// Represents a ConfigStatusEventArgs - /// - public class ConfigStatusEventArgs : EventArgs - { - /// - /// Gets or sets the UpdateStatus - /// - public eUpdateStatus UpdateStatus { get; private set; } +public class ConfigStatusEventArgs : EventArgs +{ + public eUpdateStatus UpdateStatus { get; private set; } - /// - /// ConfigStatusEventArgs Constructor - /// - /// - public ConfigStatusEventArgs(eUpdateStatus status) - { - UpdateStatus = status; - } + public ConfigStatusEventArgs(eUpdateStatus status) + { + UpdateStatus = status; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/Essentials/ConfigWriter.cs b/src/PepperDash.Essentials.Core/Config/Essentials/ConfigWriter.cs index 93517a3c..a688b378 100644 --- a/src/PepperDash.Essentials.Core/Config/Essentials/ConfigWriter.cs +++ b/src/PepperDash.Essentials.Core/Config/Essentials/ConfigWriter.cs @@ -11,174 +11,154 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Config +namespace PepperDash.Essentials.Core.Config; + +/// +/// Responsible for updating config at runtime, and writing the updates out to a local file +/// +public class ConfigWriter { - /// - /// 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"; + public const string LocalConfigFolder = "LocalConfig"; - /// - /// WriteTimeout constant - /// - public const long WriteTimeout = 30000; - - /// - /// WriteTimer variable - /// - public static CTimer WriteTimer; + public const long WriteTimeout = 30000; + 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) + /// + /// Updates the config properties of a device + /// + /// + /// + /// + 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) { - bool success = false; + // Replace the current properties JToken with the new one passed into this method + deviceConfig.Properties = properties; - // Get the current device config - var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(deviceKey)); + Debug.LogMessage(LogEventLevel.Debug, "Updated properties of device: '{0}'", 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; + success = true; } - /// - /// UpdateDeviceConfig method - /// - /// The new device config - /// True if the update was successful, otherwise false - public static bool UpdateDeviceConfig(DeviceConfig config) + ResetTimer(); + + return success; + } + + public static bool UpdateDeviceConfig(DeviceConfig config) + { + bool success = false; + + var deviceConfigIndex = ConfigReader.ConfigObject.Devices.FindIndex(d => d.Key.Equals(config.Key)); + + if (deviceConfigIndex >= 0) { - bool success = false; + ConfigReader.ConfigObject.Devices[deviceConfigIndex] = config; - var deviceConfigIndex = ConfigReader.ConfigObject.Devices.FindIndex(d => d.Key.Equals(config.Key)); + Debug.LogMessage(LogEventLevel.Debug, "Updated config of device: '{0}'", 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; + success = true; } - /// - /// UpdateRoomConfig method - /// - /// The new room config - /// True if the update was successful, otherwise false - public static bool UpdateRoomConfig(DeviceConfig config) - { - bool success = false; + ResetTimer(); + + return success; + } + + public static bool UpdateRoomConfig(DeviceConfig config) + { + bool success = false; var roomConfigIndex = ConfigReader.ConfigObject.Rooms.FindIndex(d => d.Key.Equals(config.Key)); if (roomConfigIndex >= 0) - { - ConfigReader.ConfigObject.Rooms[roomConfigIndex] = config; - - Debug.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); + ConfigReader.ConfigObject.Rooms[roomConfigIndex] = config; - WriteTimer.Reset(WriteTimeout); + Debug.LogMessage(LogEventLevel.Debug, "Updated room of device: '{0}'", config.Key); - 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(); - - } + 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 + /// + /// + /// + 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(); + + } + } + + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/Essentials/EssentialsConfig.cs b/src/PepperDash.Essentials.Core/Config/Essentials/EssentialsConfig.cs index 6ffe07d2..d9a5918f 100644 --- a/src/PepperDash.Essentials.Core/Config/Essentials/EssentialsConfig.cs +++ b/src/PepperDash.Essentials.Core/Config/Essentials/EssentialsConfig.cs @@ -9,171 +9,139 @@ using Newtonsoft.Json; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Config +namespace PepperDash.Essentials.Core.Config; + +/// +/// Loads the ConfigObject from the file +/// +public class EssentialsConfig : BasicConfig +{ + [JsonProperty("system_url")] + public string SystemUrl { get; set; } + + [JsonProperty("template_url")] + public string TemplateUrl { get; set; } + + /// + /// Gets the SystemUuid extracted from the SystemUrl + /// + [JsonProperty("systemUuid")] + public string SystemUuid + { + get + { + if (string.IsNullOrEmpty(SystemUrl)) + return "missing url"; + + if (SystemUrl.Contains("#")) + { + var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/#.*"); + string uuid = result.Groups[1].Value; + return uuid; + } + else + { + var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/.*"); + string uuid = result.Groups[1].Value; + return uuid; + } + } + } + + /// + /// Gets the TemplateUuid extracted from the TemplateUrl + /// + [JsonProperty("templateUuid")] + public string TemplateUuid + { + get + { + if (string.IsNullOrEmpty(TemplateUrl)) + return "missing template url"; + + if (TemplateUrl.Contains("#")) + { + var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/templates\/(.*)\/#.*"); + string uuid = result.Groups[1].Value; + return uuid; + } + else + { + var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/system-templates\/(.*)\/system-template-versions\/(.*)\/.*"); + string uuid = result.Groups[2].Value; + return uuid; + } + } + } + + [JsonProperty("rooms")] + public List Rooms { get; set; } + + /// + /// Gets or sets the Versions + /// + public VersionData Versions { get; set; } + + public EssentialsConfig() + : base() + { + Rooms = new List(); + } +} + +/// +/// Represents version data for Essentials and its packages +/// +public class VersionData { /// - /// Loads the ConfigObject from the file + /// Gets or sets the Essentials version /// - 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(); - } - } + [JsonProperty("essentials")] + public NugetVersion Essentials { get; set; } /// - /// Represents version data for Essentials and its packages + /// Gets or sets the list of 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(); - } - } + [JsonProperty("packages")] + public List Packages { get; set; } /// - /// Represents a NugetVersion + /// Initializes a new instance of the class. /// - public class NugetVersion + public VersionData() { - /// - /// Gets or sets the Version - /// - [JsonProperty("version")] - public string Version { get; set; } - - /// - /// Gets or sets the PackageId - /// - [JsonProperty("packageId")] - public string PackageId { get; set; } + Packages = new List(); } +} + +/// +/// Represents a NugetVersion +/// +public class NugetVersion +{ + /// + /// Gets or sets the Version + /// + [JsonProperty("version")] + public string Version { get; set; } /// - /// Represents a SystemTemplateConfigs + /// Gets or sets the PackageId /// - public class SystemTemplateConfigs - { - /// - /// Gets or sets the System - /// - public EssentialsConfig System { get; set; } + [JsonProperty("packageId")] + public string PackageId { get; set; } +} - /// - /// Gets or sets the Template - /// - public EssentialsConfig Template { get; set; } - } -} \ No newline at end of file +/// +/// +/// +public class SystemTemplateConfigs +{ + public EssentialsConfig System { get; set; } + + /// + /// Gets or sets the Template + /// + public EssentialsConfig Template { get; set; } +} diff --git a/src/PepperDash.Essentials.Core/Config/ILoadConfig.cs b/src/PepperDash.Essentials.Core/Config/ILoadConfig.cs index ed6ff61f..a02baa8c 100644 --- a/src/PepperDash.Essentials.Core/Config/ILoadConfig.cs +++ b/src/PepperDash.Essentials.Core/Config/ILoadConfig.cs @@ -4,16 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public interface ILoadConfig { - /// - /// Defines the contract for ILoadConfig - /// - public interface ILoadConfig - { - /// - /// GoWithLoad method - /// - void GoWithLoad(); - } + void GoWithLoad(); } diff --git a/src/PepperDash.Essentials.Core/Config/InfoConfig.cs b/src/PepperDash.Essentials.Core/Config/InfoConfig.cs index 1ce2c60b..7c2f81e4 100644 --- a/src/PepperDash.Essentials.Core/Config/InfoConfig.cs +++ b/src/PepperDash.Essentials.Core/Config/InfoConfig.cs @@ -5,12 +5,12 @@ 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 +namespace PepperDash.Essentials.Core.Config; + +/// +/// Represents the info section of a Config file +/// +public class InfoConfig { /// /// Gets or sets the Name @@ -70,49 +70,49 @@ namespace PepperDash.Essentials.Core.Config Type = ""; Version = ""; Comment = ""; - HostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); - AppNumber = InitialParametersClass.ApplicationNumber; + HostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); + AppNumber = InitialParametersClass.ApplicationNumber; - RuntimeInfo = new RuntimeInfo(); + RuntimeInfo = new RuntimeInfo(); } } - + +/// +/// Represents runtime information about the program/processor +/// +public class RuntimeInfo +{ /// - /// Represents a RuntimeInfo + /// The name of the running application /// - public class RuntimeInfo - { - /// - /// The name of the running application - /// - [JsonProperty("appName")] - public string AppName {get; set;} - //{ - // get - // { - // return Assembly.GetExecutingAssembly().GetName().Name; - // } - //} + [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 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;} + /// , + /// The OS Version of the processor (Firmware Version) + /// + [JsonProperty("osVersion")] + public string OsVersion {get; set;} //{ // get // { @@ -120,17 +120,15 @@ namespace PepperDash.Essentials.Core.Config // } //} - /// - /// The information gathered by the processor at runtime about it's NICs and their IP addresses. - /// - [JsonProperty("ipInfo")] - public Dictionary IpInfo + /// + /// The information gathered by the processor at runtime about it's NICs and their IP addresses. + /// + [JsonProperty("ipInfo")] + public Dictionary IpInfo + { + get { - get - { - return Global.EthernetAdapterInfoCollection; - } + return Global.EthernetAdapterInfoCollection; } } - } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/SourceDevicePropertiesConfigBase.cs b/src/PepperDash.Essentials.Core/Config/SourceDevicePropertiesConfigBase.cs index 42a576a2..ae30de0a 100644 --- a/src/PepperDash.Essentials.Core/Config/SourceDevicePropertiesConfigBase.cs +++ b/src/PepperDash.Essentials.Core/Config/SourceDevicePropertiesConfigBase.cs @@ -4,16 +4,12 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core.Config +namespace PepperDash.Essentials.Core.Config; + +public class SourceDevicePropertiesConfigBase { - /// - /// Represents a SourceDevicePropertiesConfigBase - /// - public class SourceDevicePropertiesConfigBase - { - /// - /// Gets or sets the DisableSharing - /// - public bool DisableSharing { get; set; } - } + /// + /// Gets or sets the DisableSharing + /// + public bool DisableSharing { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Crestron/CrestronGenericBaseDevice.cs b/src/PepperDash.Essentials.Core/Crestron/CrestronGenericBaseDevice.cs index bdb3e461..afb15015 100644 --- a/src/PepperDash.Essentials.Core/Crestron/CrestronGenericBaseDevice.cs +++ b/src/PepperDash.Essentials.Core/Crestron/CrestronGenericBaseDevice.cs @@ -7,11 +7,8 @@ using PepperDash.Core.JsonStandardObjects; using PepperDash.Essentials.Core.Bridges; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ - /// - /// Abstract base class for Crestron GenericBase devices - /// +namespace PepperDash.Essentials.Core; + public abstract class CrestronGenericBaseDevice : EssentialsDevice, IOnline, IHasFeedback, ICommunicationMonitor, IUsageTracking { /// @@ -19,10 +16,10 @@ namespace PepperDash.Essentials.Core /// protected GenericBase Hardware; - /// - /// Gets or sets the Feedbacks - /// - public FeedbackCollection Feedbacks { get; private set; } + /// + /// Returns a list containing the Outputs that we want to expose. + /// + public FeedbackCollection Feedbacks { get; private set; } /// /// Gets or sets the IsOnline @@ -51,30 +48,25 @@ namespace PepperDash.Essentials.Core /// name of the device /// hardware instance protected CrestronGenericBaseDevice(string key, string name, GenericBase hardware) - : base(key, name) - { - Feedbacks = new FeedbackCollection(); + : 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); + 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); - } + 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(); + protected CrestronGenericBaseDevice(string key, string name) + : base(key, name) + { + Feedbacks = new FeedbackCollection(); - } + } /// /// Registers the Crestron GenericBase hardware instance @@ -82,13 +74,13 @@ namespace PepperDash.Essentials.Core /// 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); + 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); + CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, hardware, 120000, 300000); } /// @@ -97,43 +89,43 @@ namespace PepperDash.Essentials.Core /// public override bool CustomActivate() { - Debug.LogMessage(LogEventLevel.Information, this, "Activating"); - if (!PreventRegistration) - { - //Debug.LogMessage(LogEventLevel.Debug, this, " Does not require registration. Skipping"); + Debug.LogMessage(LogEventLevel.Information, this, "Activating"); + if (!PreventRegistration) + { + //Debug.LogMessage(LogEventLevel.Debug, this, " Does not require registration. Skipping"); - if (Hardware.Registerable && !Hardware.Registered) + if (Hardware.Registerable && !Hardware.Registered) + { + var response = Hardware.RegisterWithLogging(Key); + if (response != eDeviceRegistrationUnRegistrationResponse.Success) { - var response = Hardware.RegisterWithLogging(Key); - if (response != eDeviceRegistrationUnRegistrationResponse.Success) - { - //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; } - - IsRegistered.FireUpdate(); } - else - { - AddPostActivationAction(() => + + IsRegistered.FireUpdate(); + } + else + { + AddPostActivationAction(() => + { + if (Hardware.Registerable && !Hardware.Registered) { - if (Hardware.Registerable && !Hardware.Registered) - { - var response = Hardware.RegisterWithLogging(Key); - } + var response = Hardware.RegisterWithLogging(Key); + } - IsRegistered.FireUpdate(); - }); - } + IsRegistered.FireUpdate(); + }); + } - foreach (var f in Feedbacks) - { - f.FireUpdate(); - } + foreach (var f in Feedbacks) + { + f.FireUpdate(); + } - Hardware.OnlineStatusChange += Hardware_OnlineStatusChange; - CommunicationMonitor.Start(); + Hardware.OnlineStatusChange += Hardware_OnlineStatusChange; + CommunicationMonitor.Start(); return base.CustomActivate(); } @@ -149,42 +141,42 @@ namespace PepperDash.Essentials.Core var success = Hardware.UnRegister() == eDeviceRegistrationUnRegistrationResponse.Success; - IsRegistered.FireUpdate(); + IsRegistered.FireUpdate(); - return success; + return success; } /// - /// Adds feedback(s) to the list - /// - /// feedback(s) to be added to the list - public void AddToFeedbackList(params Feedback[] newFbs) + /// Adds feedback(s) to the list + /// + /// + public void AddToFeedbackList(params Feedback[] newFbs) + { + foreach (var f in newFbs) { - foreach (var f in newFbs) - { - if (f == null) continue; + if (f == null) continue; - if (!Feedbacks.Contains(f)) - { - Feedbacks.Add(f); - } + 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); + 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. - } + 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(); - } + foreach (var feedback in Feedbacks) + { + if (feedback != null) + feedback.FireUpdate(); + } } #region IStatusMonitor Members @@ -195,52 +187,28 @@ namespace PepperDash.Essentials.Core public StatusMonitorBase CommunicationMonitor { get; private set; } #endregion - #region IUsageTracking Members + #region IUsageTracking Members - /// - /// Gets or sets the UsageTracker - /// - public UsageTracking UsageTracker { get; set; } + public UsageTracking UsageTracker { get; set; } - #endregion + #endregion } - /// - /// Abstract base class for Crestron GenericBase devices that are bridgeable - /// - public abstract class CrestronGenericBridgeableBaseDevice : CrestronGenericBaseDevice, IBridgeAdvanced +public abstract class CrestronGenericBridgeableBaseDevice : CrestronGenericBaseDevice, IBridgeAdvanced +{ + protected CrestronGenericBridgeableBaseDevice(string key, string name, GenericBase hardware) : base(key, name, hardware) { - - /// - /// 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); } + protected CrestronGenericBridgeableBaseDevice(string key, string name) + : base(key, name) + { + } + + + public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); +} + //*********************************************************************************** /// @@ -281,5 +249,4 @@ namespace PepperDash.Essentials.Core return result; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericRelayDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericRelayDevice.cs index a41e1411..15dfcd36 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericRelayDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericRelayDevice.cs @@ -13,253 +13,209 @@ using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +/// +/// Represents a generic device controlled by relays +/// +[Description("Wrapper class for a Relay")] +public class GenericRelayDevice : EssentialsBridgeableDevice, ISwitchedOutput { - /// - /// Represents a generic device controlled by relays - /// - [Description("Wrapper class for a Relay")] - public class GenericRelayDevice : EssentialsBridgeableDevice, ISwitchedOutput + public Relay RelayOutput { get; private set; } + + public BoolFeedback OutputIsOnFeedback { get; private set; } + + //Maintained for compatibility with PepperDash.Essentials.Core.Devices.CrestronProcessor + public GenericRelayDevice(string key, Relay relay) : + base(key) { - /// - /// The RelayOutput controlled by this device - /// - public Relay RelayOutput { get; private set; } + OutputIsOnFeedback = new BoolFeedback(new Func(() => RelayOutput.State)); - /// - /// Feedback to indicate whether the output is on - /// - public BoolFeedback OutputIsOnFeedback { get; private set; } + RelayOutput = relay; + RelayOutput.Register(); - //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) + RelayOutput.StateChange += RelayOutput_StateChange; + } + + public GenericRelayDevice(string key, string name, Func postActivationFunc, + IOPortConfig config) + : base(key, name) + { + OutputIsOnFeedback = new BoolFeedback(() => RelayOutput.State); + + AddPostActivationAction(() => { - 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."); - } + RelayOutput = postActivationFunc(config); if (RelayOutput == null) { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Relay is null", Key); + Debug.LogMessage(LogEventLevel.Information, this, "Unable to get parent relay device for device key {0} and port {1}", config.PortDeviceKey, config.PortNumber); 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 - + 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 + + public void OpenRelay() + { + RelayOutput.State = false; + } + + public void CloseRelay() + { + RelayOutput.State = true; + } + + 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 + + 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 + + public class GenericRelayDeviceFactory : EssentialsDeviceFactory + { + public GenericRelayDeviceFactory() + { + TypeNames = new List() { "relayoutput" }; + } + + 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 + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs index ad5507d0..d9deb961 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs @@ -1,6 +1,4 @@ - - -using System; +using System; using System.Collections.Generic; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs index 47e8aef6..2088e952 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs @@ -1,6 +1,4 @@ - - -using System; +using System; using System.Collections.Generic; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs index ee3f0320..39c26cd6 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs @@ -11,173 +11,176 @@ using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +/// +/// Represents a generic digital input deviced tied to a versiport +/// +public class GenericVersiportDigitalOutputDevice : EssentialsBridgeableDevice, IDigitalOutput { - /// - /// Represents a generic digital input deviced tied to a versiport - /// - public class GenericVersiportDigitalOutputDevice : EssentialsBridgeableDevice, IDigitalOutput, IHasFeedback + public Versiport OutputPort { get; private set; } + + public BoolFeedback OutputStateFeedback { get; private set; } + + Func OutputStateFeedbackFunc { - 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) + get { - 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; - - }); + return () => OutputPort.DigitalOut; } + } - void OutputPort_VersiportChange(Versiport port, VersiportEventArgs args) + public GenericVersiportDigitalOutputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : + base(key, name) + { + OutputStateFeedback = new BoolFeedback(OutputStateFeedbackFunc); + + AddPostActivationAction(() => { - this.LogDebug("Versiport change: {event}", args.Event); + OutputPort = postActivationFunc(config); - if (args.Event == eVersiportEvent.DigitalOutChange) - OutputStateFeedback.FireUpdate(); - } + OutputPort.Register(); - /// - /// Set value of the versiport digital output - /// - /// value to set the output to - public void SetOutput(bool state) - { - if (!outputPort.SupportsDigitalOutput) + + if (!OutputPort.SupportsDigitalOutput) { - this.LogError("Versiport does not support Digital Output Mode"); + Debug.LogMessage(LogEventLevel.Information, this, "Device does not support configuration as a Digital Output"); return; } - outputPort.DigitalOut = state; - } + OutputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalOutput); - #region Bridge Linking - /// - /// LinkToApi method - /// - /// - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - var joinMap = new IDigitalOutputJoinMap(joinStart); + OutputPort.VersiportChange += OutputPort_VersiportChange; - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + }); - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + } - if (bridge != null) + void OutputPort_VersiportChange(Versiport port, VersiportEventArgs args) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Versiport change: {0}", args.Event); + + if(args.Event == eVersiportEvent.DigitalOutChange) + OutputStateFeedback.FireUpdate(); + } + + /// + /// Set value of the versiport digital output + /// + /// value to set the output to + public void SetOutput(bool state) + { + if (OutputPort.SupportsDigitalOutput) { - bridge.AddJoinMap(Key, joinMap); + Debug.LogMessage(LogEventLevel.Information, this, "Passed the Check"); + + OutputPort.DigitalOut = state; + } else { - this.LogWarning("Please update config to use 'eiscapiadvanced' to get all join map features for this device."); + Debug.LogMessage(LogEventLevel.Information, this, "Versiport does not support Digital Output Mode"); } - 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: "); - } + #region Bridge Linking + + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + var joinMap = new IDigitalOutputJoinMap(joinStart); + + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + + if (bridge != null) + { + bridge.AddJoinMap(Key, joinMap); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } - #endregion - - - /// - /// GetVersiportDigitalOutput method - /// - public static Versiport GetVersiportDigitalOutput(IOPortConfig dc) + try { + Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + + // Link feedback for input state + OutputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.OutputState.JoinNumber]); + trilist.SetBoolSigAction(joinMap.OutputState.JoinNumber, SetOutput); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); + Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); + } + } + + #endregion + + + public static Versiport GetVersiportDigitalOutput(IOPortConfig dc) + { + + IIOPorts ioPortDevice; + if (dc.PortDeviceKey.Equals("processor")) { if (!Global.ControlSystem.SupportsVersiport) { - Debug.LogError("GetVersiportDigitalOutput: Processor does not support Versiports"); + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Processor does not support Versiports"); return null; } - return Global.ControlSystem.VersiPorts[dc.PortNumber]; + ioPortDevice = Global.ControlSystem; } - - if (!(DeviceManager.GetDeviceForKey(dc.PortDeviceKey) is IIOPorts ioPortDevice)) + else { - Debug.LogError("GetVersiportDigitalOutput: Device {key} is not a valid device", dc.PortDeviceKey); + var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; + if (ioPortDev == null) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Device {0} is not a valid device", dc.PortDeviceKey); + return null; + } + ioPortDevice = ioPortDev; + } + if (ioPortDevice == null) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Device '0' is not a valid IOPorts 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; + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); } - return ioPortDevice.VersiPorts[dc.PortNumber]; - } + var port = ioPortDevice.VersiPorts[dc.PortNumber]; + return port; + + } +} + + +public class GenericVersiportDigitalOutputDeviceFactory : EssentialsDeviceFactory +{ + public GenericVersiportDigitalOutputDeviceFactory() + { + TypeNames = new List() { "versiportoutput" }; } - - /// - /// Represents a GenericVersiportDigitalOutputDeviceFactory - /// - public class GenericVersiportDigitalOutputDeviceFactory : EssentialsDeviceFactory + public override EssentialsDevice BuildDevice(DeviceConfig dc) { - /// - /// Initialize a new instance of the class. - /// - public GenericVersiportDigitalOutputDeviceFactory() - { - TypeNames = new List() { "versiportoutput" }; - } + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Versiport Device"); - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogDebug("Factory Attempting to create new Generic Versiport Device"); + var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); - var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); + if (props == null) return null; - if (props == null) return null; + var portDevice = new GenericVersiportDigitalOutputDevice(dc.Key, dc.Name, GenericVersiportDigitalOutputDevice.GetVersiportDigitalOutput, props); - var portDevice = new GenericVersiportDigitalOutputDevice(dc.Key, dc.Name, GenericVersiportDigitalOutputDevice.GetVersiportDigitalOutput, props); - - return portDevice; - } + return portDevice; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs b/src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs index 426834ed..c42e273c 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs @@ -5,7 +5,9 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +public interface IAnalogInput { /// /// Defines the contract for IAnalogInput diff --git a/src/PepperDash.Essentials.Core/CrestronIO/IDigitalInput.cs b/src/PepperDash.Essentials.Core/CrestronIO/IDigitalInput.cs index 8e1b4c18..963fa8b1 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/IDigitalInput.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/IDigitalInput.cs @@ -1,19 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Core.CrestronIO; -namespace PepperDash.Essentials.Core.CrestronIO + +/// +/// Represents a device that provides digital input +/// +public interface IDigitalInput { /// - /// Represents a device that provides digital input + /// Feedback to indicate the state of the input /// - public interface IDigitalInput - { - /// - /// Feedback to indicate the state of the input - /// - BoolFeedback InputStateFeedback { get; } - } -} \ No newline at end of file + BoolFeedback InputStateFeedback { get; } +} diff --git a/src/PepperDash.Essentials.Core/CrestronIO/IDigitalOutput.cs b/src/PepperDash.Essentials.Core/CrestronIO/IDigitalOutput.cs index 82aa0686..7c4f720a 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/IDigitalOutput.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/IDigitalOutput.cs @@ -4,7 +4,12 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +/// +/// Represents a device that provides digital input +/// +public interface IDigitalOutput { /// /// Represents a device that provides digital input diff --git a/src/PepperDash.Essentials.Core/CrestronIO/IHasCresnetBranches.cs b/src/PepperDash.Essentials.Core/CrestronIO/IHasCresnetBranches.cs index ee86b5fe..b882f50e 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/IHasCresnetBranches.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/IHasCresnetBranches.cs @@ -6,7 +6,12 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines the contract for a class that has Cresnet branches +/// +public interface IHasCresnetBranches { /// /// Defines the contract for IHasCresnetBranches diff --git a/src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs b/src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs index 7b76958b..f89b3b0f 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs @@ -1,5 +1,4 @@  - using System; using System.Collections.Generic; using System.Linq; diff --git a/src/PepperDash.Essentials.Core/CrestronIO/ISwitchedOutput.cs b/src/PepperDash.Essentials.Core/CrestronIO/ISwitchedOutput.cs index 30b4b8f9..9f5bec7b 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/ISwitchedOutput.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/ISwitchedOutput.cs @@ -6,37 +6,36 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +/// +/// Describes an output capable of switching on and off +/// +public interface ISwitchedOutput { /// - /// Describes an output capable of switching on and off + /// Feedback to indicate the state of the output /// - 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(); - } + BoolFeedback OutputIsOnFeedback {get;} /// - /// Describes a collection of switched outputs + /// Turns the output on /// - public interface ISwitchedOutputCollection - { - /// - /// Dictionary of switched outputs by their port number - /// - Dictionary SwitchedOutputs { get; } - } + void On(); + + /// + /// Turns the output off + /// + void Off(); +} + +/// +/// Defines the contract for a class that has a collection of switched outputs +/// +public interface ISwitchedOutputCollection +{ + /// + /// Collection of switched outputs, indexed by their output number + /// + Dictionary SwitchedOutputs { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Device Info/DeviceInfo.cs b/src/PepperDash.Essentials.Core/Device Info/DeviceInfo.cs index 6e55c9b3..abd011ef 100644 --- a/src/PepperDash.Essentials.Core/Device Info/DeviceInfo.cs +++ b/src/PepperDash.Essentials.Core/Device Info/DeviceInfo.cs @@ -1,29 +1,28 @@ -namespace PepperDash.Essentials.Core.DeviceInfo +namespace PepperDash.Essentials.Core.DeviceInfo; + +/// +/// Represents a DeviceInfo +/// +public class DeviceInfo { /// - /// Represents a DeviceInfo + /// Gets or sets the HostName /// - 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; } - } -} \ No newline at end of file + 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; } +} diff --git a/src/PepperDash.Essentials.Core/Device Info/DeviceInfoEventArgs.cs b/src/PepperDash.Essentials.Core/Device Info/DeviceInfoEventArgs.cs index 266b0d0b..df4ea69d 100644 --- a/src/PepperDash.Essentials.Core/Device Info/DeviceInfoEventArgs.cs +++ b/src/PepperDash.Essentials.Core/Device Info/DeviceInfoEventArgs.cs @@ -1,32 +1,32 @@ using System; -namespace PepperDash.Essentials.Core.DeviceInfo +namespace PepperDash.Essentials.Core.DeviceInfo; + + +/// +/// Represents a DeviceInfoEventArgs +/// +public class DeviceInfoEventArgs : EventArgs { /// - /// Represents a DeviceInfoEventArgs + /// Gets or sets the DeviceInfo /// - public class DeviceInfoEventArgs:EventArgs + public DeviceInfo DeviceInfo { get; set; } + + /// + /// Constructor + /// + public DeviceInfoEventArgs() { - /// - /// 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; - } } -} \ No newline at end of file + + /// + /// Constructor with DeviceInfo + /// + /// the DeviceInfo instance + public DeviceInfoEventArgs(DeviceInfo devInfo) + { + DeviceInfo = devInfo; + } +} diff --git a/src/PepperDash.Essentials.Core/Device Info/IDeviceInfoProvider.cs b/src/PepperDash.Essentials.Core/Device Info/IDeviceInfoProvider.cs index 3f5a4735..d4dc0852 100644 --- a/src/PepperDash.Essentials.Core/Device Info/IDeviceInfoProvider.cs +++ b/src/PepperDash.Essentials.Core/Device Info/IDeviceInfoProvider.cs @@ -1,31 +1,31 @@ using System; using PepperDash.Core; -namespace PepperDash.Essentials.Core.DeviceInfo +namespace PepperDash.Essentials.Core.DeviceInfo; + +/// +/// Defines the contract for IDeviceInfoProvider +/// +public interface IDeviceInfoProvider : IKeyed { /// - /// Defines the contract for IDeviceInfoProvider + /// Gets the DeviceInfo /// - public interface IDeviceInfoProvider:IKeyed - { - /// - /// Gets the DeviceInfo - /// - DeviceInfo DeviceInfo { get; } - - /// - /// Event fired when DeviceInfo changes - /// - event DeviceInfoChangeHandler DeviceInfoChanged; - - /// - /// Updates the DeviceInfo - /// - void UpdateDeviceInfo(); - } + DeviceInfo DeviceInfo { get; } /// - /// Delegate for DeviceInfoChangeHandler + /// Event fired when DeviceInfo changes /// - public delegate void DeviceInfoChangeHandler(IKeyed device, DeviceInfoEventArgs args); -} \ No newline at end of file + event DeviceInfoChangeHandler DeviceInfoChanged; + + /// + /// Updates the DeviceInfo + /// + void UpdateDeviceInfo(); +} + +/// +/// Delegate for DeviceInfoChangeHandler +/// +public delegate void DeviceInfoChangeHandler(IKeyed device, DeviceInfoEventArgs args); + diff --git a/src/PepperDash.Essentials.Core/Device Info/NetworkDeviceHelpers.cs b/src/PepperDash.Essentials.Core/Device Info/NetworkDeviceHelpers.cs index 79eaa018..14390754 100644 --- a/src/PepperDash.Essentials.Core/Device Info/NetworkDeviceHelpers.cs +++ b/src/PepperDash.Essentials.Core/Device Info/NetworkDeviceHelpers.cs @@ -6,233 +6,213 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.DeviceInfo +namespace PepperDash.Essentials.Core.DeviceInfo; + +public static class NetworkDeviceHelpers { /// - /// Static class NetworkDeviceHelpers + /// Event raised when ArpTable changes /// - public static class NetworkDeviceHelpers + 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(); + + /// + /// Last resolved ARP table - it is recommended to refresh the arp before using this. + /// + public static List ArpTable { get; private set; } + + /// + /// Force recheck of ARP table + /// + public static void RefreshArp() { - /// - /// 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 { - var error = false; - try + Lock.Enter(); + var consoleResponse = string.Empty; + if (!CrestronConsole.SendControlSystemCommand("showarptable", ref consoleResponse)) return; + if (string.IsNullOrEmpty(consoleResponse)) { - 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; + return; } - finally + 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) { - Lock.Leave(); - OnArpTableUpdated(new ArpTableEventArgs(ArpTable, error)); + 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)); } } - - - private static void OnArpTableUpdated(ArpTableEventArgs args) + catch (Exception ex) { - if (args == null) return; - var handler = ArpTableUpdated; - if (handler == null) return; - handler.Invoke(args); + Debug.LogMessage(LogEventLevel.Information, "Exception in \"RefreshArp\" : {0}", ex.Message); + error = true; } - - static NetworkDeviceHelpers() + finally { - ArpTable = new List(); + Lock.Leave(); + OnArpTableUpdated(new ArpTableEventArgs(ArpTable, error)); } + } - /// - /// 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; - } - } + 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(); } /// - /// Represents a ArpEntry + /// Removes leading zeros, leading whitespace, and trailing whitespace from an IPAddress string /// - public class ArpEntry + /// Ip Address to Santitize + /// Sanitized Ip Address + public static string SanitizeIpAddress(string ipAddressIn) { - /// - /// 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) + try { - 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; + 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; } } /// - /// Represents a ArpTableEventArgs + /// Resolves a hostname by IP Address using DNS /// - public class ArpTableEventArgs : EventArgs + /// IP Address to resolve from + /// Resolved Hostname - on failure to determine hostname, will return IP Address + public static string ResolveHostnameFromIp(string ipAddress) { - /// - /// 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) + try { - ArpTable = arpTable; - Error = error; + var santitizedIp = SanitizeIpAddress(ipAddress); + var hostEntry = Dns.GetHostEntry(santitizedIp); + return hostEntry == null ? ipAddress : hostEntry.HostName; } - - /// - /// Constructor for ArpTableEventArgs - assumes no error encountered in retrieving ARP Table - /// - /// The entirety of the retrieved ARP table - public ArpTableEventArgs(List arpTable) + catch (Exception ex) { - ArpTable = arpTable; - Error = false; + 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 + 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; + } + } + +} + +/// +/// Object to hold data about an arp entry +/// +public class ArpEntry +{ + public readonly IPAddress IpAddress; + 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; + } +} + +/// +/// Arguments passed by the ArpTableUpdated event +/// +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; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IChannel.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IChannel.cs index c8c54006..3dda43e4 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IChannel.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IChannel.cs @@ -4,8 +4,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Defines the contract for IChannel /// @@ -79,5 +79,4 @@ namespace PepperDash.Essentials.Core triList.ClearBoolSigAction(129); triList.ClearBoolSigAction(134); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IColorFunctions.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IColorFunctions.cs index 69acc8f6..51f8e44a 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IColorFunctions.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IColorFunctions.cs @@ -4,8 +4,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// IColor interface /// @@ -66,5 +66,4 @@ namespace PepperDash.Essentials.Core triList.ClearBoolSigAction(157); triList.ClearBoolSigAction(158); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDPad.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDPad.cs index ec9362b8..9e26cd5a 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDPad.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDPad.cs @@ -4,8 +4,8 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -86,5 +86,4 @@ namespace PepperDash.Essentials.Core triList.ClearBoolSigAction(130); triList.ClearBoolSigAction(134); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDiscPlayerControls.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDiscPlayerControls.cs index 5deee690..b3d944e6 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDiscPlayerControls.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDiscPlayerControls.cs @@ -3,14 +3,11 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; /// /// Defines the contract for IDiscPlayerControls /// public interface IDiscPlayerControls : IColor, IDPad, INumericKeypad, IHasPowerControl, ITransport, IUiDisplayInfo { - } - -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs index af3428f6..3f38d4e4 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs @@ -1,15 +1,14 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +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 { - /// - /// 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 - { - } } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplayBasic.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplayBasic.cs index b76d3145..e744ac15 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplayBasic.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplayBasic.cs @@ -1,14 +1,10 @@ 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 /// + [Obsolete("This interface is no longer used and will be removed in a future version. Please use IDisplay instead.")] public interface IDisplayBasic { /// diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDumbSource.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDumbSource.cs index 2f419498..ba7f1a43 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDumbSource.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDumbSource.cs @@ -4,12 +4,11 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines the contract for IDumbSource +/// +public interface IDumbSource { - /// - /// Defines the contract for IDumbSource - /// - public interface IDumbSource - { - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDvr.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDvr.cs index 527e8d46..4397db50 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDvr.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDvr.cs @@ -9,8 +9,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -55,5 +55,4 @@ namespace PepperDash.Essentials.Core triList.ClearBoolSigAction(136); triList.ClearBoolSigAction(152); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IEmergencyOSD.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IEmergencyOSD.cs index efc068b0..66d74c3e 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IEmergencyOSD.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IEmergencyOSD.cs @@ -1,25 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces + +/// +/// Defines the contract for IEmergencyOSD +/// +public interface IEmergencyOSD { /// - /// Defines the contract for IEmergencyOSD + /// Shows an emergency message on the OSD /// - public interface IEmergencyOSD - { - /// - /// Shows an emergency message on the OSD - /// - /// The URL of the emergency message to display - void ShowEmergencyMessage(string url); + /// The URL of the emergency message to display + void ShowEmergencyMessage(string url); - /// - /// Hides the emergency message from the OSD - /// - void HideEmergencyMessage(); - } + /// + /// Hides the emergency message from the OSD + /// + void HideEmergencyMessage(); } + diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasBranding.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasBranding.cs index c05ef572..75f04156 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasBranding.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasBranding.cs @@ -1,21 +1,18 @@ -using System; +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +/// +/// Defines the contract for IHasBranding +/// +public interface IHasBranding { /// - /// Defines the contract for IHasBranding + /// Gets whether branding is enabled /// - public interface IHasBranding - { - /// - /// Gets whether branding is enabled - /// - bool BrandingEnabled { get; } + bool BrandingEnabled { get; } - /// - /// Initializes branding for the device - /// - /// The key identifying the room for branding purposes - void InitializeBranding(string roomKey); - } -} \ No newline at end of file + /// + /// Initializes branding for the device + /// + /// The key identifying the room for branding purposes + void InitializeBranding(string roomKey); +} diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasFarEndContentStatus.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasFarEndContentStatus.cs index 5a8f66ee..1595fa6e 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasFarEndContentStatus.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasFarEndContentStatus.cs @@ -1,13 +1,13 @@ -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + + +/// +/// Defines the contract for IHasFarEndContentStatus +/// +public interface IHasFarEndContentStatus { /// - /// Defines the contract for IHasFarEndContentStatus + /// Gets whether far end content is being received /// - public interface IHasFarEndContentStatus - { - /// - /// Gets whether far end content is being received - /// - BoolFeedback ReceivingContent { get; } - } -} \ No newline at end of file + BoolFeedback ReceivingContent { get; } +} diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasInputs.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasInputs.cs index 42e97b4b..d6fae39d 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasInputs.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasInputs.cs @@ -1,19 +1,20 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +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 { /// - /// Describes a device that has selectable inputs + /// Gets the collection of 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; } - } + ISelectableItems Inputs { get; } } + diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasPhoneDialing.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasPhoneDialing.cs index b884092b..170b058d 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasPhoneDialing.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasPhoneDialing.cs @@ -1,43 +1,40 @@ -using System; -using PepperDash.Essentials.Core; +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces + +/// +/// Defines the contract for IHasPhoneDialing +/// +public interface IHasPhoneDialing { /// - /// Defines the contract for IHasPhoneDialing + /// Feedback that indicates whether the phone is off-hook /// - public interface IHasPhoneDialing - { - /// - /// Feedback that indicates whether the phone is off-hook - /// - BoolFeedback PhoneOffHookFeedback { get; } + BoolFeedback PhoneOffHookFeedback { get; } - /// - /// Feedback that provides the caller ID name - /// - StringFeedback CallerIdNameFeedback { get; } + /// + /// Feedback that provides the caller ID name + /// + StringFeedback CallerIdNameFeedback { get; } - /// - /// Feedback that provides the caller ID number - /// - StringFeedback CallerIdNumberFeedback { 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); + /// + /// Dials a phone call to the specified number + /// + /// the number to dial + void DialPhoneCall(string number); - /// - /// Ends the current phone call - /// - void EndPhoneCall(); + /// + /// Ends the current phone call + /// + void EndPhoneCall(); - /// - /// Sends a DTMF digit to the phone - /// - /// the DTMF digit to send - void SendDtmfToPhone(string digit); - } -} \ No newline at end of file + /// + /// Sends a DTMF digit to the phone + /// + /// the DTMF digit to send + void SendDtmfToPhone(string digit); +} diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasScreensWithLayouts.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasScreensWithLayouts.cs index 439462c6..2a67e39b 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasScreensWithLayouts.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasScreensWithLayouts.cs @@ -5,103 +5,102 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +/// +/// This defines a device that has screens with layouts +/// Simply decorative +/// +public interface IHasScreensWithLayouts { /// - /// This defines a device that has screens with layouts - /// Simply decorative + /// A dictionary of screens, keyed by screen ID, that contains information about each screen and its layouts. /// - 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); - } + Dictionary Screens { get; } /// - /// Represents information about a screen and its layouts. + /// Applies a specific layout to a screen based on the provided screen ID and layout index. /// - 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; } - } + /// + /// + 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; } } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasSurroundSoundModes.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasSurroundSoundModes.cs index 45b24f8b..2a50dd0f 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasSurroundSoundModes.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasSurroundSoundModes.cs @@ -1,9 +1,4 @@ using PepperDash.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasWebView.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasWebView.cs index 396229ce..d1ae55bd 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasWebView.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasWebView.cs @@ -1,87 +1,84 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + + +/// +/// Defines the contract for IHasWebView +/// +public interface IHasWebView { /// - /// Defines the contract for IHasWebView + /// Indicates whether the webview is currently visible /// - 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; - } - + bool WebviewIsVisible { get; } /// - /// Defines the contract for IHasWebViewWithPwaMode + /// Shows the webview with the specified parameters /// - 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(); - } - + /// 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); /// - /// Represents a WebViewStatusChangedEventArgs + /// Hides the webview /// - public class WebViewStatusChangedEventArgs : EventArgs - { - /// - /// Gets or sets the Status - /// - public string Status { get; } + void HideWebView(); - /// - /// Constructor for WebViewStatusChangedEventArgs - /// - /// the new status of the webview - public WebViewStatusChangedEventArgs(string status) - { - Status = status; - } + /// + /// 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; } + + /// + /// Constructor for WebViewStatusChangedEventArgs + /// + /// the new status of the webview + public WebViewStatusChangedEventArgs(string status) + { + Status = status; } } + diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHumiditySensor.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHumiditySensor.cs index 748fb860..f28059c3 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHumiditySensor.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHumiditySensor.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - + namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageDefinition.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageDefinition.cs index f02c0e05..4cdffc83 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageDefinition.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageDefinition.cs @@ -1,56 +1,57 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + + +/// +/// Defines the contract for ILanguageDefinition +/// +public interface ILanguageDefinition { /// - /// Defines the contract for ILanguageDefinition + /// The locale name for the language definition /// - public interface ILanguageDefinition - { - /// - /// The locale name for the language definition - /// - string LocaleName { get; set; } + string LocaleName { get; set; } - /// - /// The friendly name for the language definition - /// - string FriendlyName { get; set; } + /// + /// The friendly name for the language definition + /// + string FriendlyName { get; set; } - /// - /// Indicates whether the language definition is enabled - /// - bool Enable { 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 UI labels for the language definition + /// + List UiLabels { get; set; } - /// - /// The source and destination labels for the language definition - /// - List Sources { 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 destination labels for the language definition + /// + List Destinations { get; set; } - /// - /// The source group names for the language definition - /// - List SourceGroupNames { 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 destination group names for the language definition + /// + List DestinationGroupNames { get; set; } - /// - /// The room names for the language definition - /// - List RoomNames { get; set; } - } + /// + /// The room names for the language definition + /// + List RoomNames { get; set; } } + diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageProvider.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageProvider.cs index 9ac22d2b..ac9544ea 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageProvider.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageProvider.cs @@ -1,22 +1,21 @@ using System; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +/// +/// Defines the contract for ILanguageProvider +/// +public interface ILanguageProvider { - /// - /// Defines the contract for ILanguageProvider + /// The current language definition /// - public interface ILanguageProvider - { - /// - /// The current language definition - /// - ILanguageDefinition CurrentLanguage { get; set; } - - /// - /// Event raised when the current language changes - /// - event EventHandler CurrentLanguageChanged; - } + ILanguageDefinition CurrentLanguage { get; set; } + /// + /// Event raised when the current language changes + /// + event EventHandler CurrentLanguageChanged; } + + diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILevelControls.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILevelControls.cs index e0a1081f..d4876e3c 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILevelControls.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILevelControls.cs @@ -4,16 +4,17 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + + +/// +/// Defines the contract for ILevelControls +/// +public interface ILevelControls { /// - /// Defines the contract for ILevelControls + /// The level control points /// - public interface ILevelControls - { - /// - /// The level control points - /// - Dictionary LevelControlPoints { get; } - } + Dictionary LevelControlPoints { get; } } + diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs index 0b1760fa..f920e5fe 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs @@ -2,71 +2,70 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + + +/// +/// Defines the contract for IMobileControl +/// +public interface IMobileControl : IKeyed { + /// + /// Gets the Host + /// + string Host { get; } /// - /// Defines the contract for IMobileControl + /// Gets the Client App URL /// - public interface IMobileControl : IKeyed - { - /// - /// Gets the Host - /// - string Host { get; } + string ClientAppUrl { get; } - /// - /// Gets the Client App URL - /// - string ClientAppUrl { get; } + /// + /// Gets the System UUID + /// + string SystemUuid { get; } - /// - /// Gets the System UUID - /// - string SystemUuid { get; } + /// + /// Gets the ApiOnlineAndAuthorized feedback + /// + BoolFeedback ApiOnlineAndAuthorized { get; } - /// - /// Gets the ApiOnlineAndAuthorized feedback - /// - BoolFeedback ApiOnlineAndAuthorized { get; } + /// + /// Sends the message object to the AppServer + /// + /// Message to send + void SendMessageObject(IMobileControlMessage o); - /// - /// 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; - /// - /// 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); - /// - /// Removes an action for a messenger - /// - /// key for action - void RemoveAction(string key); + /// + /// Adds a device messenger + /// + /// Messenger to add + void AddDeviceMessenger(IMobileControlMessenger messenger); - /// - /// 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); - /// - /// 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); - } -} \ No newline at end of file + /// + /// Get a Room Messenger by key + /// + /// messenger key to find + /// Messenger if found, null otherwise + IMobileControlRoomMessenger GetRoomMessenger(string key); +} diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPasswordPrompt.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPasswordPrompt.cs index 2ee85341..a068ba19 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPasswordPrompt.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPasswordPrompt.cs @@ -4,63 +4,62 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Describes the functionality required to prompt a user to enter a password +/// +public interface IPasswordPrompt { /// - /// Describes the functionality required to prompt a user to enter a password + /// Notifies when a password is required or is entered incorrectly /// - 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); - } + event EventHandler PasswordRequired; /// - /// PasswordPromptEventArgs class + /// Submits the password /// - public class PasswordPromptEventArgs : EventArgs + /// + void SubmitPassword(string password); +} + +/// +/// Event args for password prompt events +/// +public class PasswordPromptEventArgs : EventArgs +{ + /// + /// Indicates if the last submitted password was incorrect + /// + public bool LastAttemptWasIncorrect { get; private set; } + + /// + /// Indicates that the login attempt has failed + /// + public bool LoginAttemptFailed { get; private set; } + + /// + /// Indicates that the process was cancelled and the prompt should be dismissed + /// + public bool LoginAttemptCancelled { get; private set; } + + /// + /// A message to be displayed to the user + /// + public string Message { get; private set; } + + /// + /// Constructor for password prompt event args + /// + /// Indicates if the last submitted password was incorrect + /// Indicates that the login attempt has failed + /// Indicates that the process was cancelled and the prompt should be dismissed + /// A message to be displayed to the user + public PasswordPromptEventArgs(bool lastAttemptIncorrect, bool loginFailed, bool loginCancelled, string message) { - /// - /// 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; - } + LastAttemptWasIncorrect = lastAttemptIncorrect; + LoginAttemptFailed = loginFailed; + LoginAttemptCancelled = loginCancelled; + Message = message; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPower.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPower.cs index b94a64ed..a94dfe12 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPower.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPower.cs @@ -1,86 +1,77 @@ -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 Crestron.SimplSharpPro.DeviceSupport; +namespace PepperDash.Essentials.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.SmartObjects; +/// +/// Adds feedback for current power state +/// +public interface IHasPowerControlWithFeedback : IHasPowerControl +{ + /// + /// Feedback indicating whether the device is powered on + /// + BoolFeedback PowerIsOnFeedback { get; } +} -namespace PepperDash.Essentials.Core + +/// +/// 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 { /// - /// Adds feedback for current power state + /// LinkButtons method /// - public interface IHasPowerControlWithFeedback : IHasPowerControl + public static void LinkButtons(this IHasPowerControl dev, BasicTriList triList) { - /// - /// Feedback indicating whether the device is powered on - /// - BoolFeedback PowerIsOnFeedback { get; } + 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]); + } } /// - /// Defines the ability to power a device on and off + /// UnlinkButtons method /// - public interface IHasPowerControl + public static void UnlinkButtons(this IHasPowerControl dev, BasicTriList triList) { - /// - /// Powers the device on - /// - void PowerOn(); + triList.ClearBoolSigAction(101); + triList.ClearBoolSigAction(102); + triList.ClearBoolSigAction(103); - /// - /// Powers the device off - /// - void PowerOff(); - - /// - /// Toggles the power state of the device - /// - void PowerToggle(); + var fbdev = dev as IHasPowerControlWithFeedback; + if (fbdev != null) + { + fbdev.PowerIsOnFeedback.UnlinkInputSig(triList.BooleanInput[101]); + } } - - /// - /// 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]); - } - } - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IProjectorScreenLiftControl.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IProjectorScreenLiftControl.cs index 56aef09e..efa3a0c4 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IProjectorScreenLiftControl.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IProjectorScreenLiftControl.cs @@ -3,8 +3,8 @@ using System; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces -{ +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + /// /// Defines the contract for IProjectorScreenLiftControl /// @@ -60,5 +60,4 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces /// Screen type device /// screen - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItem.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItem.cs index ff05188e..410cf563 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItem.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItem.cs @@ -2,28 +2,28 @@ using Newtonsoft.Json; using PepperDash.Core; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + + + +/// +/// Defines the contract for ISelectableItem +/// +public interface ISelectableItem : IKeyName { + /// + /// Raised when the item is updated + /// + event EventHandler ItemUpdated; /// - /// Defines the contract for ISelectableItem + /// Gets or sets whether the item is selected /// - public interface ISelectableItem : IKeyName - { - /// - /// Raised when the item is updated - /// - event EventHandler ItemUpdated; + [JsonProperty("isSelected")] + bool IsSelected { get; set; } - /// - /// Gets or sets whether the item is selected - /// - [JsonProperty("isSelected")] - bool IsSelected { get; set; } - - /// - /// Selects the item - /// - void Select(); - } -} \ No newline at end of file + /// + /// Selects the item + /// + void Select(); +} diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItems.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItems.cs index c955a56f..94a03a51 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItems.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItems.cs @@ -2,42 +2,41 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + + +/// +/// Defines the contract for ISelectableItems +/// +public interface ISelectableItems where TValue : ISelectableItem { /// - /// Defines the contract for ISelectableItems + /// Raised when the items are updated /// - 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; } - - } + event EventHandler ItemsUpdated; /// - /// Describes a collection of items that can be selected + /// Raised when the current item changes /// - /// type for the keys in the collection. Probably a string or enum - public interface ISelectableItems : ISelectableItems - { - } + 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 +{ } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISetTopBoxControls.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISetTopBoxControls.cs index d8bf969e..e195f16f 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISetTopBoxControls.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISetTopBoxControls.cs @@ -3,8 +3,8 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Defines the contract for ISetTopBoxControls /// @@ -81,5 +81,4 @@ namespace PepperDash.Essentials.Core triList.ClearBoolSigAction(136); triList.ClearBoolSigAction(152); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITemperatureSensor.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITemperatureSensor.cs index 897855b4..e6b09f8b 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITemperatureSensor.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITemperatureSensor.cs @@ -1,31 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces + +/// +/// Defines the contract for ITemperatureSensor +/// +public interface ITemperatureSensor { /// - /// Defines the contract for 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. /// - 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; } + IntFeedback TemperatureFeedback { get; } - /// - /// The temperature in Celsius format - /// - BoolFeedback TemperatureInCFeedback { 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); - } + /// + /// Sets the temperature format to Celsius or Fahrenheit + /// + /// If true, sets the format to Celsius; otherwise, sets it to Fahrenheit. + void SetTemperatureFormat(bool setToC); } + diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITransport.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITransport.cs index 917a4b19..4ff2d6ab 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITransport.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITransport.cs @@ -1,98 +1,97 @@ using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines the contract for ITransport +/// +public interface ITransport { - /// - /// 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) { - /// - /// 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); + 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); } /// - /// ITransportExtensions class + /// UnlinkButtons method /// - public static class ITransportExtensions + /// The ITransport device + /// The BasicTriList to unlink buttons from + public static void UnlinkButtons(this ITransport dev, BasicTriList triList) { - /// - /// 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); - } + triList.ClearBoolSigAction(145); + triList.ClearBoolSigAction(146); + triList.ClearBoolSigAction(147); + triList.ClearBoolSigAction(148); + triList.ClearBoolSigAction(149); + triList.ClearBoolSigAction(150); + triList.ClearBoolSigAction(151); + triList.ClearBoolSigAction(154); } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITvPresetsProvider.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITvPresetsProvider.cs index 09b7066c..0d6fce71 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITvPresetsProvider.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITvPresetsProvider.cs @@ -1,15 +1,14 @@ using PepperDash.Essentials.Core.Presets; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +/// +/// Defines the contract for ITvPresetsProvider +/// +public interface ITvPresetsProvider { /// - /// Defines the contract for ITvPresetsProvider + /// The TV presets model /// - public interface ITvPresetsProvider - { - /// - /// The TV presets model - /// - DevicePresetsModel TvPresets { get; } - } -} \ No newline at end of file + DevicePresetsModel TvPresets { get; } +} diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IUiDisplayInfo.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IUiDisplayInfo.cs index 231abf1f..274cb06a 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IUiDisplayInfo.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IUiDisplayInfo.cs @@ -1,7 +1,7 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Defines the contract for IUiDisplayInfo /// @@ -11,5 +11,4 @@ namespace PepperDash.Essentials.Core /// Display UI Type /// uint DisplayUiType { get; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IWarmingCooling.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IWarmingCooling.cs index e69bf35c..54ac37f8 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IWarmingCooling.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IWarmingCooling.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Defines a class that has warm up and cool down /// @@ -20,5 +20,4 @@ namespace PepperDash.Essentials.Core /// Feedback indicating whether the device is cooling down /// BoolFeedback IsCoolingDownFeedback { get; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/LanguageLabel.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/LanguageLabel.cs index c8a45592..7f83a829 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/LanguageLabel.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/LanguageLabel.cs @@ -1,28 +1,26 @@ -using System; -using PepperDash.Core; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces + +/// +/// Represents a LanguageLabel +/// +public class LanguageLabel { /// - /// Represents a LanguageLabel + /// Gets or sets the Key /// - 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; } - } -} \ No newline at end of file + 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; } +} diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/Template.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/Template.cs index 31f71df9..bf8dedd6 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/Template.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/Template.cs @@ -3,7 +3,6 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ - -} \ No newline at end of file +namespace PepperDash.Essentials.Core; + + \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/AudioControlListItemBase.cs b/src/PepperDash.Essentials.Core/Devices/AudioControlListItemBase.cs index 038f80a7..ec555c79 100644 --- a/src/PepperDash.Essentials.Core/Devices/AudioControlListItemBase.cs +++ b/src/PepperDash.Essentials.Core/Devices/AudioControlListItemBase.cs @@ -5,41 +5,40 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Base class for items that can be added to an AudioControlList. Contains properties that are common to all items, such as the parent device key and an optional item key. Also includes properties for display purposes, such as a name and order. +/// +public abstract class AudioControlListItemBase { /// - /// Base class for audio control list items + /// Key of the parent device in the DeviceManager /// - public abstract class AudioControlListItemBase - { - /// - /// Key of the parent device in the DeviceManager - /// - [JsonProperty("parentDeviceKey")] - public string ParentDeviceKey { get; set; } + [JsonProperty("parentDeviceKey")] + public string ParentDeviceKey { get; set; } - /// - /// Optional key of the item in the parent device - /// - [JsonProperty("itemKey")] - public string ItemKey { 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; } + /// + /// 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; } + /// + /// 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; } - } + /// + /// Used to specify the order of the items in the source list when displayed + /// + [JsonProperty("order")] + public int Order { get; set; } } diff --git a/src/PepperDash.Essentials.Core/Devices/AudioInterfaces.cs b/src/PepperDash.Essentials.Core/Devices/AudioInterfaces.cs index cc886636..a9e0dc92 100644 --- a/src/PepperDash.Essentials.Core/Devices/AudioInterfaces.cs +++ b/src/PepperDash.Essentials.Core/Devices/AudioInterfaces.cs @@ -6,8 +6,8 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Enumeration of AudioChangeType values @@ -50,5 +50,4 @@ namespace PepperDash.Essentials.Core ChangeType = changeType; AudioDevice = device; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/CameraListItem.cs b/src/PepperDash.Essentials.Core/Devices/CameraListItem.cs index a154c083..91ca3c83 100644 --- a/src/PepperDash.Essentials.Core/Devices/CameraListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/CameraListItem.cs @@ -1,82 +1,82 @@ using Newtonsoft.Json; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents an item in a camera list, which can be used to display camera sources in a user interface. Contains properties for the device key, preferred name, icon, and order of the item in the list. Also includes a property to get the associated camera device from the DeviceManager based on the device key. +/// +public class CameraListItem { + /// - /// Represents a CameraListItem + /// Key of the camera device in the DeviceManager /// - public class CameraListItem + [JsonProperty("deviceKey")] + public string DeviceKey { get; set; } + + /// + /// Returns the source Device for this, if it exists in DeviceManager + /// + [JsonIgnore] + public Device CameraDevice { - /// - /// 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 { - get - { - if (_cameraDevice == null) - _cameraDevice = DeviceManager.GetDeviceForKey(DeviceKey) as Device; - return _cameraDevice; - } + 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; } } + 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; } } diff --git a/src/PepperDash.Essentials.Core/Devices/CodecInterfaces.cs b/src/PepperDash.Essentials.Core/Devices/CodecInterfaces.cs index b9d8a28f..d757cd5a 100644 --- a/src/PepperDash.Essentials.Core/Devices/CodecInterfaces.cs +++ b/src/PepperDash.Essentials.Core/Devices/CodecInterfaces.cs @@ -4,107 +4,106 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +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 { /// - /// Adds control of codec receive volume + /// Sets the transmit volume level /// - 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; } - } + /// volume level to set + void SetTransmitVolume(ushort level); /// - /// Defines the contract for ITransmitVolume + /// Mutes the transmit audio /// - 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; } - } + void TransmitMuteOn(); /// - /// Defines the contract for IPrivacy + /// Unmutes the transmit audio /// - public interface IPrivacy - { - /// - /// Enables privacy mode - /// - void PrivacyModeOn(); + void TransmitMuteOff(); - /// - /// Disables privacy mode - /// - void PrivacyModeOff(); + /// + /// Toggles the transmit mute state + /// + void TransmitMuteToggle(); - /// - /// Toggles privacy mode - /// - void PrivacyModeToggle(); + /// + /// Feedback for the transmit volume level + /// + IntFeedback TransmitLevelFeedback { get; } - /// - /// Feedback for the privacy mode state - /// - BoolFeedback PrivacyModeIsOnFeedback { get; } - } -} \ No newline at end of file + /// + /// 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; } +} diff --git a/src/PepperDash.Essentials.Core/Devices/CrestronProcessor.cs b/src/PepperDash.Essentials.Core/Devices/CrestronProcessor.cs index 8c31d4c6..29481b34 100644 --- a/src/PepperDash.Essentials.Core/Devices/CrestronProcessor.cs +++ b/src/PepperDash.Essentials.Core/Devices/CrestronProcessor.cs @@ -8,56 +8,45 @@ using PepperDash.Core; using PepperDash.Essentials.Core.CrestronIO; using Serilog.Events; -namespace PepperDash.Essentials.Core.Devices +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 { - /// - /// This wrapper class is meant to allow interfaces to be applied to any Crestron processor - /// - public class CrestronProcessor : Device, ISwitchedOutputCollection + public Dictionary SwitchedOutputs { get; private set; } + + public Crestron.SimplSharpPro.CrestronControlSystem Processor { get; private set; } + + public CrestronProcessor(string key) + : base(key) { - /// - /// Collection of switched outputs (relays) on the processor - /// - public Dictionary SwitchedOutputs { get; private set; } + SwitchedOutputs = new Dictionary(); + Processor = Global.ControlSystem; - /// - /// The underlying CrestronControlSystem processor - /// - public Crestron.SimplSharpPro.CrestronControlSystem Processor { get; private set; } + GetRelays(); + } - /// - /// Constructor - /// - /// key for the processor - public CrestronProcessor(string key) - : base(key) + /// + /// Creates a GenericRelayDevice for each relay on the processor and adds them to the SwitchedOutputs collection + /// + void GetRelays() + { + try { - 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) { - if (Processor.SupportsRelay) + for (uint i = 1; i <= Processor.NumberOfRelayPorts; i++) { - 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); - } + 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); - } + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Error Getting Relays from processor:\n '{0}'", e); } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs index 5a66c0b3..03f7af0e 100644 --- a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs @@ -3,122 +3,123 @@ using Newtonsoft.Json; using PepperDash.Essentials.Core; -namespace 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 { + /// - /// 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. + /// Gets or sets the key identifier for the sink device that this destination represents. /// - public class DestinationListItem + [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 { - /// - /// 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; } + 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; } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/DeviceApiBase.cs b/src/PepperDash.Essentials.Core/Devices/DeviceApiBase.cs index 28ac13dc..9d15b256 100644 --- a/src/PepperDash.Essentials.Core/Devices/DeviceApiBase.cs +++ b/src/PepperDash.Essentials.Core/Devices/DeviceApiBase.cs @@ -4,21 +4,20 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core.Devices +namespace PepperDash.Essentials.Core.Devices; + +/// +/// Base class for all Device APIs +/// +public abstract class DeviceApiBase { /// - /// Base class for all Device APIs + /// Action API dictionary /// - public abstract class DeviceApiBase - { - /// - /// Action API dictionary - /// - public Dictionary ActionApi { get; protected set; } + public Dictionary ActionApi { get; protected set; } - /// - /// Feedback API dictionary - /// - public Dictionary FeedbackApi { get; protected set; } - } -} \ No newline at end of file + /// + /// Feedback API dictionary + /// + public Dictionary FeedbackApi { get; protected set; } +} diff --git a/src/PepperDash.Essentials.Core/Devices/DeviceFeedbackExtensions.cs b/src/PepperDash.Essentials.Core/Devices/DeviceFeedbackExtensions.cs index 0e7595e1..e8bb635a 100644 --- a/src/PepperDash.Essentials.Core/Devices/DeviceFeedbackExtensions.cs +++ b/src/PepperDash.Essentials.Core/Devices/DeviceFeedbackExtensions.cs @@ -6,30 +6,29 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Extension methods for working with device feedback properties. +/// +public static class DeviceFeedbackExtensions { /// - /// DeviceFeedbackExtensions class + /// Attempts to get and return a feedback property from a device by name. + /// If unsuccessful, returns null. /// - public static class DeviceFeedbackExtensions + /// + /// + /// + public static Feedback GetFeedbackProperty(this Device device, string propertyName) { - /// - /// 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) { - var feedback = DeviceJsonApi.GetPropertyByName(device.Key, propertyName) as Feedback; - - if (feedback != null) - { - return feedback; - } - - return null; + return feedback; } + + return null; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs b/src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs index c4ec2ca9..6ba640d4 100644 --- a/src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs +++ b/src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs @@ -9,528 +9,530 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Provides methods for interacting with devices using JSON-formatted commands. +/// +public class DeviceJsonApi { /// - /// Represents a DeviceJsonApi + /// Executes a method on a device based on a JSON-formatted command string. /// - public class DeviceJsonApi + /// + public static void DoDeviceActionWithJson(string json) { - /// - /// DoDeviceActionWithJson method - /// - /// json method - public static void DoDeviceActionWithJson(string json) + if (String.IsNullOrEmpty(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]}"); + } + + } + + + /// + /// Executes a method on a device based on a JSON-formatted command string, awaiting the result if the method is asynchronous. + /// + /// + 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( - "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."); + "Unable to find method with name {0} and that matches parameters {1}", action.MethodName, + action.Params); return; } - try - { - var action = JsonConvert.DeserializeObject(json); + var mParams = method.GetParameters(); - DoDeviceAction(action); - } - catch (Exception) - { - CrestronConsole.ConsoleCommandResponse("Incorrect format for JSON. Please check that the format matches {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}"); - } + var convertedParams = mParams + .Select((p, i) => ConvertType(action.Params[i], p.ParameterType)) + .ToArray(); - } - - - /// - /// 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) + Task.Run(() => { try { - return PropInfo.GetValue(Parent, null).ToString(); + Debug.LogMessage(LogEventLevel.Verbose, "Calling method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey); + method.Invoke(obj, convertedParams); } - catch (Exception) + 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); + } + } + + /// + /// Executes a method on a device based on a JSON-formatted command string, awaiting the result if the method is asynchronous. + /// + /// + /// + 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-formatted 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 retrieve. + /// The value of the property, or a JSON-formatted error string if the device or property is not found. + 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-formatted 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, which are the methods marked with the ApiAttribute. + /// These are the methods intended to be called through the JSON API. + /// This allows for hiding certain methods from the API if desired. + /// + /// The path to the device object. + /// A JSON-formatted 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); + } + + + /// + /// Walks down a dotted object path, starting with a Device, and returns the object + /// at the end of the 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 - return null; + obj = prop.GetValue(obj, 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; - } + return obj; } /// - /// Represents a MethodNameParams + /// Sets a property on an object. /// - public class MethodNameParams + /// + /// + public static string SetProperty(string deviceObjectPath) { - /// - /// Gets or sets the MethodInfo - /// - [JsonIgnore] - public MethodInfo MethodInfo { get; private set; } + throw new NotImplementedException("This could be really useful. Finish it please"); - /// - /// Gets or sets the Name - /// - public string Name { get { return MethodInfo.Name; } } + //var obj = FindObjectOnPath(deviceObjectPath); + //if (obj == null) + // return "{\"error\":\"No object found\"}"; - /// - /// Gets or sets the Params - /// - public IEnumerable Params + //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); + } + + +} + +/// +/// Attribute to mark methods as part of the JSON API. Only methods marked with this attribute will be returned by GetApiMethods and intended to be called through the JSON API. +/// +public class DeviceActionWrapper +{ + /// + /// The key of the device to call the method on + /// + public string DeviceKey { get; set; } + + /// + /// The name of the method to call + /// + public string MethodName { get; set; } + + /// + /// The parameters to pass to the method. This should be an array of objects matching the parameters of the method being called. If the method has no parameters, this can be omitted or set to null. + /// + public object[] Params { get; set; } +} + +/// +/// Helper class for serializing properties with their name, type, and value, and whether they can be read or written to. +/// +public class PropertyNameType +{ + private object Parent; + + /// + /// The PropertyInfo for the property being represented. This is ignored for JSON serialization. + /// + [JsonIgnore] + public PropertyInfo PropInfo { get; private set; } + + /// + /// The name of the property + /// + public string Name { get { return PropInfo.Name; } } + + /// + /// The type of the property + /// + public string Type { get { return PropInfo.PropertyType.Name; } } + + /// + /// The value of the property, or null if the property cannot be read or an error occurs when trying to read it. + /// + public string Value + { + get { - get + if (PropInfo.CanRead) { - return MethodInfo.GetParameters().Select(p => - new NameType { Name = p.Name, Type = p.ParameterType.Name }); + try + { + return PropInfo.GetValue(Parent, null).ToString(); + } + catch (Exception) + { + return null; + } } + else + return null; } + } - /// - /// MethodNameParams constructor - /// - /// method info - public MethodNameParams(MethodInfo info) + /// + /// Indicates whether the property can be read from + /// + public bool CanRead { get { return PropInfo.CanRead; } } + /// + /// Indicates whether the property can be written to + /// + public bool CanWrite { get { return PropInfo.CanWrite; } } + + + /// + /// Constructor + /// + /// + /// + public PropertyNameType(PropertyInfo info, object parent) + { + PropInfo = info; + Parent = parent; + } +} + +/// +/// Helper class for serializing methods with their name and parameters. The MethodInfo is ignored for JSON serialization. +/// +public class MethodNameParams +{ + /// + /// The MethodInfo for the method being represented. This is ignored for JSON serialization. + /// + [JsonIgnore] + public MethodInfo MethodInfo { get; private set; } + + /// + /// The name of the method + /// + public string Name { get { return MethodInfo.Name; } } + + /// + /// The parameters of the method, represented as an array of NameType objects with the parameter name and type. + /// + public IEnumerable Params + { + get { - MethodInfo = info; + return MethodInfo.GetParameters().Select(p => + new NameType { Name = p.Name, Type = p.ParameterType.Name }); } } /// - /// Represents a NameType + /// Constructor /// - public class NameType + /// + public MethodNameParams(MethodInfo info) { - /// - /// Gets or sets the Name - /// - public string Name { get; set; } - /// - /// Gets or sets the Type - /// - public string Type { get; set; } + MethodInfo = info; } +} + +/// +/// Helper class for serializing a name and type pair, used for method parameters in MethodNameParams. +/// +public class NameType +{ + /// + /// The name of the parameter + /// + public string Name { get; set; } /// - /// Represents a ApiAttribute + /// The type of the parameter /// - [AttributeUsage(AttributeTargets.All)] - public class ApiAttribute : Attribute - { + public string Type { get; set; } +} + +/// +/// Attribute to mark methods as part of the JSON API. Only methods marked with this attribute will be returned by GetApiMethods and intended to be called through the JSON API. +/// +[AttributeUsage(AttributeTargets.All)] +public class ApiAttribute : Attribute +{ - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/DisplayUiConstants.cs b/src/PepperDash.Essentials.Core/Devices/DisplayUiConstants.cs index 1c6ae244..39e7067b 100644 --- a/src/PepperDash.Essentials.Core/Devices/DisplayUiConstants.cs +++ b/src/PepperDash.Essentials.Core/Devices/DisplayUiConstants.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Integers that represent the "source type number" for given sources. /// Primarily used by the UI to calculate subpage join offsets @@ -62,5 +62,4 @@ namespace PepperDash.Essentials.Core /// TypeNoControls constant /// public const uint TypeNoControls = 49; - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsBridgeableDevice.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsBridgeableDevice.cs index 0b1a5ff7..23b06e9a 100644 --- a/src/PepperDash.Essentials.Core/Devices/EssentialsBridgeableDevice.cs +++ b/src/PepperDash.Essentials.Core/Devices/EssentialsBridgeableDevice.cs @@ -1,31 +1,17 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core.Bridges; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public abstract class EssentialsBridgeableDevice:EssentialsDevice, IBridgeAdvanced { - /// - /// Base class for devices that can be bridged to an EISC API. - /// - public abstract class EssentialsBridgeableDevice : EssentialsDevice, IBridgeAdvanced + protected EssentialsBridgeableDevice(string key) : base(key) { - /// - /// 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); } + + protected EssentialsBridgeableDevice(string key, string name) : base(key, name) + { + } + + public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs index 41b46c29..3b4f3789 100644 --- a/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs +++ b/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs @@ -5,185 +5,225 @@ using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core +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 { /// - /// Defines the basic needs for an EssentialsDevice to enable it to be build by an IDeviceFactory class + /// Event that fires when the device has completed initialization. This is useful for any setup that needs to occur after all devices have been activated. /// - [Description("The base Essentials Device Class")] - public abstract class EssentialsDevice : Device + public event EventHandler Initialized; + + private bool _isInitialized; + + /// + /// Indicates whether the device has completed initialization. Initialization occurs after all devices have been activated, and is triggered by the DeviceManager.AllDevicesActivated event. This property can be used to determine when it is safe to perform actions that require all devices to be active. + /// + public bool IsInitialized { - /// - /// 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 { - get { return _isInitialized; } - private set + if (_isInitialized == value) return; + + _isInitialized = value; + + if (_isInitialized) { - if (_isInitialized == value) return; - - _isInitialized = value; - - if (_isInitialized) - { - Initialized?.Invoke(this, new EventArgs()); - } + 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() - { - - } - } - - [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] - public class DescriptionAttribute : Attribute - { - private string _Description; - - public DescriptionAttribute(string description) - { - //Debug.LogMessage(LogEventLevel.Verbose, "Setting Description: {0}", description); - _Description = description; - } - - public string Description - { - get { return _Description; } - } - } - - [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] - public class ConfigSnippetAttribute : Attribute - { - private string _ConfigSnippet; - - public ConfigSnippetAttribute(string configSnippet) - { - //Debug.LogMessage(LogEventLevel.Verbose, "Setting Config Snippet {0}", configSnippet); - _ConfigSnippet = configSnippet; - } - - public string ConfigSnippet - { - get { return _ConfigSnippet; } - } } /// - /// Represents a factory for creating processor extension devices. + /// Constructor /// - /// The type of the processor extension device. - public abstract class ProcessorExtensionDeviceFactory : IProcessorExtensionDeviceFactory where T : EssentialsDevice + /// + protected EssentialsDevice(string key) + : base(key) { - #region IProcessorExtensionDeviceFactory Members - - /// - /// 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; } - - /// - /// Loads an item to the ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods dictionary for each entry in the TypeNames list - /// - public void LoadFactories() - { - foreach (var typeName in TypeNames) - { - //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName); - var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[]; - string description = descriptionAttribute[0].Description; - var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[]; - 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 - + SubscribeToActivateComplete(); } /// - /// Devices the basic needs for a Device Factory + /// Constructor /// - public abstract class EssentialsPluginDeviceFactory : EssentialsDeviceFactory, IPluginDeviceFactory where T : EssentialsDevice + /// + /// + protected EssentialsDevice(string key, string name) + : base(key, name) { - /// - /// 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; } + 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); + } + }); + } + + /// + /// Override this method to perform any initialization that requires all devices to be activated. This method is called automatically after the DeviceManager.AllDevicesActivated event is fired, and should not be called directly. + /// + /// + 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() + { + + } +} + +/// +/// Provides a description for a device that can be used in the UI and other areas where a human-readable description of the device is needed. +/// +[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] +public class DescriptionAttribute : Attribute +{ + private string _Description; + + /// + /// Constructor + /// + /// + public DescriptionAttribute(string description) + { + //Debug.LogMessage(LogEventLevel.Verbose, "Setting Description: {0}", description); + _Description = description; + } + + /// + /// Gets the description of the device + /// + public string Description + { + get { return _Description; } + } +} + +/// +/// Provides a configuration snippet for a device that can be used in the UI and other areas where a sample configuration of the device is needed. This is especially useful for plugin developers to provide users with an example of how to configure their device. +/// +[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] +public class ConfigSnippetAttribute : Attribute +{ + private string _ConfigSnippet; + + /// + /// Constructor + /// + /// + public ConfigSnippetAttribute(string configSnippet) + { + //Debug.LogMessage(LogEventLevel.Verbose, "Setting Config Snippet {0}", configSnippet); + _ConfigSnippet = configSnippet; + } + + /// + /// Gets the configuration snippet for the device + /// + public string ConfigSnippet + { + get { return _ConfigSnippet; } + } +} + +/// +/// Provides a base class for creating device factories specifically designed for processor extension development in the Essentials framework. This class implements the IProcessorExtensionDeviceFactory interface and provides a structure for defining type names and building devices based on a DeviceConfig object. +/// +/// The type of device that this factory creates. Must derive from . +public abstract class ProcessorExtensionDeviceFactory : IProcessorExtensionDeviceFactory where T : EssentialsDevice +{ + #region IProcessorExtensionDeviceFactory Members + + /// + /// 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; } + + /// + /// Loads an item to the ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods dictionary for each entry in the TypeNames list + /// + public void LoadFactories() + { + foreach (var typeName in TypeNames) + { + //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName); + var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[]; + string description = descriptionAttribute[0].Description; + var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[]; + 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 + +} + +/// +/// 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; } +} + +/// +/// Provides a base class for creating device factories specifically designed for plugin development in the Essentials +/// framework. +/// +/// This class is intended to be used by developers creating plugins for the Essentials framework. It +/// includes properties to specify the minimum required Essentials framework version and to track framework versions +/// used during development. +/// The type of device that this factory creates. Must derive from . +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; } + + /// + /// A list of Essentials framework versions that were used during the development of the plugin. This can be used to track which versions of the framework the plugin is compatible with, and can be helpful for users when determining whether a plugin will work with their current version of the Essentials framework. + /// + public List DevelopmentEssentialsFrameworkVersions { get; protected set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs index bf635c0c..3f105628 100644 --- a/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs @@ -2,31 +2,29 @@ using System.Collections.Generic; using PepperDash.Essentials.Core.Config; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Devices the basic needs for a Device Factory +/// +public abstract class EssentialsDeviceFactory : IDeviceFactory where T:EssentialsDevice { + #region IDeviceFactory Members + + /// + public Type FactoryType => typeof(T); + /// - /// Devices the basic needs for a Device Factory + /// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device /// - public abstract class EssentialsDeviceFactory : IDeviceFactory where T:EssentialsDevice - { - #region IDeviceFactory Members + public List TypeNames { get; protected set; } - /// - 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; } - - /// - /// The method that will build the device - /// - /// The device config - /// An instance of the device - public abstract EssentialsDevice BuildDevice(DeviceConfig dc); - - #endregion - } + /// + /// The method that will build the device + /// + /// The device config + /// An instance of the device + public abstract EssentialsDevice BuildDevice(DeviceConfig dc); + #endregion } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/GenericIRController.cs b/src/PepperDash.Essentials.Core/Devices/GenericIRController.cs index a55235e6..77bb4fc3 100644 --- a/src/PepperDash.Essentials.Core/Devices/GenericIRController.cs +++ b/src/PepperDash.Essentials.Core/Devices/GenericIRController.cs @@ -11,84 +11,68 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Bridges.JoinMaps; using Serilog.Events; -namespace PepperDash.Essentials.Core.Devices +namespace PepperDash.Essentials.Core.Devices; + +public class GenericIrController: EssentialsBridgeableDevice { - /// - /// 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; + + public string[] IrCommands {get { return _port.IrFileCommands; }} + + public GenericIrController(string key, string name, IrOutputPortController irPort) : base(key, name) { - //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) { - _port = irPort; - if (_port == null) - { - Debug.LogMessage(LogEventLevel.Information, this, "IR Port is null, device will not function"); - return; - } - DeviceManager.AddDevice(_port); + Debug.LogMessage(LogEventLevel.Information, this, "IR Port is null, device will not function"); + return; + } + DeviceManager.AddDevice(_port); - _port.DriverLoaded.OutputChange += DriverLoadedOnOutputChange; + _port.DriverLoaded.OutputChange += DriverLoadedOnOutputChange; + } + + private void DriverLoadedOnOutputChange(object sender, FeedbackEventArgs args) + { + if (!args.BoolValue) + { + return; } - private void DriverLoadedOnOutputChange(object sender, FeedbackEventArgs args) + if (_trilist == null || _bridge == null) { - if (!args.BoolValue) - { - return; - } - - if (_trilist == null || _bridge == null) - { - return; - } - - LinkToApi(_trilist, _joinStart, _joinMapKey, _bridge); + return; } - #region Overrides of EssentialsBridgeableDevice + LinkToApi(_trilist, _joinStart, _joinMapKey, _bridge); + } - /// - /// LinkToApi method - /// - /// - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + #region Overrides of EssentialsBridgeableDevice + + 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) { - //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; - } + _trilist = trilist; + _joinStart = joinStart; + _joinMapKey = joinMapKey; + _bridge = bridge; + return; + } - var joinMap = new GenericIrControllerJoinMap(joinStart); + var joinMap = new GenericIrControllerJoinMap(joinStart); - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (_port.UseBridgeJoinMap) { @@ -150,56 +134,42 @@ namespace PepperDash.Essentials.Core.Devices } } - joinMap.PrintJoinMapInfo(); + 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) + if (bridge != null) { - _port.PressRelease(command, pressRelease); + 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."); } } - /// - /// Represents a GenericIrControllerFactory - /// - public class GenericIrControllerFactory : EssentialsDeviceFactory + #endregion + + public void Press(string command, bool pressRelease) { - /// - /// 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 + _port.PressRelease(command, pressRelease); } +} + +public class GenericIrControllerFactory : EssentialsDeviceFactory +{ + public GenericIrControllerFactory() + { + TypeNames = new List {"genericIrController"}; + } + #region Overrides of EssentialsDeviceFactory + + 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 } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/GenericMonitoredTcpDevice.cs b/src/PepperDash.Essentials.Core/Devices/GenericMonitoredTcpDevice.cs index 148a9cac..f43bf8a3 100644 --- a/src/PepperDash.Essentials.Core/Devices/GenericMonitoredTcpDevice.cs +++ b/src/PepperDash.Essentials.Core/Devices/GenericMonitoredTcpDevice.cs @@ -8,10 +8,10 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Devices -{ +namespace PepperDash.Essentials.Core.Devices; + /// - /// Represents a GenericCommunicationMonitoredDevice + /// A device that monitors the communication status of a communication client. Useful for monitoring TCP, serial, or telnet clients. /// public class GenericCommunicationMonitoredDevice : Device, ICommunicationMonitor { @@ -77,5 +77,4 @@ namespace PepperDash.Essentials.Core.Devices CommunicationMonitor.Stop(); return true; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/IAttachVideoStatusExtensions.cs b/src/PepperDash.Essentials.Core/Devices/IAttachVideoStatusExtensions.cs index 83914f6f..4d28fa18 100644 --- a/src/PepperDash.Essentials.Core/Devices/IAttachVideoStatusExtensions.cs +++ b/src/PepperDash.Essentials.Core/Devices/IAttachVideoStatusExtensions.cs @@ -4,42 +4,41 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Interface for devices that can be attached to a port that provides video status information. Provides an extension method for getting that status information. +/// +public static class IAttachVideoStatusExtensions { /// - /// IAttachVideoStatusExtensions class + /// Gets the VideoStatusOutputs for the device /// - public static class IAttachVideoStatusExtensions + /// + /// Attached VideoStatusOutputs or the default if none attached + public static VideoStatusOutputs GetVideoStatuses(this IAttachVideoStatus attachedDev) { - /// - /// 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) { - // 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; + // 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; - } + /// + /// HasVideoStatuses method + /// + public static bool HasVideoStatuses(this IAttachVideoStatus attachedDev) + { + return TieLineCollection.Default.FirstOrDefault(t => + t.SourcePort.ParentDevice == attachedDev + && t.DestinationPort is RoutingInputPortWithVideoStatuses) != null; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs b/src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs index 330538e0..9752d0e7 100644 --- a/src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs +++ b/src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs @@ -48,42 +48,40 @@ namespace PepperDash.Essentials.Core /// public static void DumpFeedbacksToConsole(this IHasFeedback source, bool getCurrentStates) { + Type t = source.GetType(); + // get the properties and set them into a new collection of NameType wrappers + var props = t.GetProperties().Select(p => new PropertyNameType(p, t)); + 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) + Debug.LogMessage(LogEventLevel.Information, source, "\n\nAvailable feedbacks:"); + foreach (var f in feedbacks) { - if (feedback is BoolFeedback) + string val = ""; + string type = ""; + if (getCurrentStates) { - 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"; + if (f is BoolFeedback) + { + val = f.BoolValue.ToString(); + type = "boolean"; + } + else if (f is IntFeedback) + { + val = f.IntValue.ToString(); + type = "integer"; + } + else if (f is StringFeedback) + { + val = f.StringValue; + type = "string"; + } } + Debug.LogMessage(LogEventLevel.Information, "{0,-12} {1, -25} {2}", type, + (string.IsNullOrEmpty(f.Key) ? "-no key-" : f.Key), val); } - CrestronConsole.ConsoleCommandResponse($" {type,-12} {(string.IsNullOrEmpty(feedback.Key) ? "-no key-" : feedback.Key),-25} {value}\r\n"); } } } diff --git a/src/PepperDash.Essentials.Core/Devices/IProjectorInterfaces.cs b/src/PepperDash.Essentials.Core/Devices/IProjectorInterfaces.cs index d6473e64..d43c6e3b 100644 --- a/src/PepperDash.Essentials.Core/Devices/IProjectorInterfaces.cs +++ b/src/PepperDash.Essentials.Core/Devices/IProjectorInterfaces.cs @@ -1,41 +1,34 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; +namespace PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core +/// +/// Defines the contract for IBasicVideoMute +/// +public interface IBasicVideoMute { /// - /// Defines the contract for IBasicVideoMute + /// Toggles the video mute /// - public interface IBasicVideoMute - { - /// - /// Toggles the video mute - /// - void VideoMuteToggle(); - } + void VideoMuteToggle(); +} + +/// +/// Defines the contract for IBasicVideoMuteWithFeedback +/// +public interface IBasicVideoMuteWithFeedback : IBasicVideoMute +{ + /// + /// Gets the VideoMuteIsOn feedback + /// + BoolFeedback VideoMuteIsOn { get; } /// - /// Defines the contract for IBasicVideoMuteWithFeedback + /// Sets the video mute on /// - public interface IBasicVideoMuteWithFeedback : IBasicVideoMute - { - /// - /// Gets the VideoMuteIsOn feedback - /// - BoolFeedback VideoMuteIsOn { get; } + void VideoMuteOn(); - /// - /// Sets the video mute on - /// - void VideoMuteOn(); + /// + /// Sets the video mute off + /// + void VideoMuteOff(); - /// - /// Sets the video mute off - /// - void VideoMuteOff(); - - } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Core/Devices/IReconfigurableDevice.cs b/src/PepperDash.Essentials.Core/Devices/IReconfigurableDevice.cs index 245c0a5c..7dca4f32 100644 --- a/src/PepperDash.Essentials.Core/Devices/IReconfigurableDevice.cs +++ b/src/PepperDash.Essentials.Core/Devices/IReconfigurableDevice.cs @@ -6,27 +6,27 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core.Config; -namespace PepperDash.Essentials.Core.Devices +namespace PepperDash.Essentials.Core.Devices; + + +/// +/// Defines the contract for IReconfigurableDevice +/// +public interface IReconfigurableDevice { /// - /// Defines the contract for IReconfigurableDevice + /// Event fired when the configuration changes /// - public interface IReconfigurableDevice - { - /// - /// Event fired when the configuration changes - /// - event EventHandler ConfigChanged; + event EventHandler ConfigChanged; - /// - /// Gets the current DeviceConfig - /// - DeviceConfig Config { get; } + /// + /// Gets the current DeviceConfig + /// + DeviceConfig Config { get; } - /// - /// Sets the DeviceConfig - /// - /// config to set - void SetConfig(DeviceConfig config); - } -} \ No newline at end of file + /// + /// Sets the DeviceConfig + /// + /// config to set + void SetConfig(DeviceConfig config); +} diff --git a/src/PepperDash.Essentials.Core/Devices/IUsageTracking.cs b/src/PepperDash.Essentials.Core/Devices/IUsageTracking.cs index 7edce646..4a45f0cc 100644 --- a/src/PepperDash.Essentials.Core/Devices/IUsageTracking.cs +++ b/src/PepperDash.Essentials.Core/Devices/IUsageTracking.cs @@ -6,143 +6,99 @@ using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public interface IUsageTracking { - /// - /// Defines the contract for IUsageTracking - /// - public interface IUsageTracking + UsageTracking UsageTracker { get; set; } +} + +//public static class IUsageTrackingExtensions +//{ +// public static void EnableUsageTracker(this IUsageTracking device) +// { +// device.UsageTracker = new UsageTracking(); +// } +//} + +public class UsageTracking +{ + public event EventHandler DeviceUsageEnded; + + public InUseTracking InUseTracker { get; protected set; } + + public bool UsageIsTracked { get; set; } + + public bool UsageTrackingStarted { get; protected set; } + public DateTime UsageStartTime { get; protected set; } + public DateTime UsageEndTime { get; protected set; } + + public Device Parent { get; private set; } + + public UsageTracking(Device parent) { - /// - /// Gets or sets the UsageTracker - /// - UsageTracking UsageTracker { get; set; } + 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(); + } } - //public static class IUsageTrackingExtensions - //{ - // public static void EnableUsageTracker(this IUsageTracking device) - // { - // device.UsageTracker = new UsageTracking(); - // } - //} /// - /// Represents a UsageTracking + /// Stores the usage start time /// - public class UsageTracking + public void StartDeviceUsage() { - /// - /// Event fired when device usage ends - /// - public event EventHandler DeviceUsageEnded; + UsageTrackingStarted = true; + UsageStartTime = DateTime.Now; + } - /// - /// 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) + /// + /// 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 { - Parent = parent; - - InUseTracker = new InUseTracking(); + UsageTrackingStarted = false; - InUseTracker.InUseFeedback.OutputChange += InUseFeedback_OutputChange; //new EventHandler(); - } + UsageEndTime = DateTime.Now; - void InUseFeedback_OutputChange(object sender, EventArgs e) - { - if(InUseTracker.InUseFeedback.BoolValue) + if (UsageStartTime != null) { - StartDeviceUsage(); - } - else - { - EndDeviceUsage(); - } - } + var timeUsed = UsageEndTime - UsageStartTime; + var handler = DeviceUsageEnded; - /// - /// 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) + if (handler != 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 }); - } + 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); - } + } + 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; } - } +public class DeviceUsageEventArgs : EventArgs +{ + public DateTime UsageEndTime { get; set; } + public int MinutesUsed { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs b/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs index 1f122735..feb6c126 100644 --- a/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs +++ b/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs @@ -1,232 +1,223 @@ - - -using System; -using System.Collections.Generic; -using System.Linq; -using Crestron.SimplSharp; +using System; 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 +namespace PepperDash.Essentials.Core; + + +/// +/// IR port wrapper. May act standalone +/// +public class IrOutputPortController : Device { + uint IrPortUid; + IROutputPort IrPort; /// - /// IR port wrapper. May act standalone + /// Gets the DriverLoaded feedback /// - public class IrOutputPortController : Device - { - uint IrPortUid; - IROutputPort IrPort; + public BoolFeedback DriverLoaded { get; private set; } - /// - /// Gets the DriverLoaded feedback - /// - public BoolFeedback DriverLoaded { get; private set; } + /// + /// Gets or sets the StandardIrPulseTime + /// + public ushort StandardIrPulseTime { get; 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 DriverFilepath - /// - public string DriverFilepath { get; private set; } + /// + /// Gets or sets the DriverIsLoaded + /// + public bool DriverIsLoaded { 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 IrFileCommands - /// - public string[] IrFileCommands { get { return IrPort.AvailableStandardIRCmds(IrPortUid); } } + /// + /// Gets or sets the UseBridgeJoinMap + /// + public bool UseBridgeJoinMap { get; private set; } - /// - /// 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"); - /// - /// 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) + DriverLoaded = new BoolFeedback(() => DriverIsLoaded); + IrPort = port; + if (port == null) { - //if (port == null) throw new ArgumentNullException("port"); + Debug.LogMessage(LogEventLevel.Information, this, "WARNING No valid IR Port assigned to controller. IR will not function"); + return; + } + LoadDriver(irDriverFilepath); + } - DriverLoaded = new BoolFeedback(() => DriverIsLoaded); - IrPort = port; - if (port == null) + /// + /// 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; } - 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); + // var filePath = Global.FilePathPrefix + "ir" + Global.DirectorySeparator + config.Properties["control"]["irFile"].Value(); - 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 fileName = config.Properties["control"]["irFile"].Value(); + var files = Directory.GetFiles(Global.FilePathPrefix, fileName, SearchOption.AllDirectories); - 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 == 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; + } - if(files.Length > 1) - { - this.LogError("IR file {fileName} found in multiple locations: {files}", fileName, files); - return; - } + var filePath = files[0]; - var filePath = files[0]; + Debug.LogMessage(LogEventLevel.Debug, "*************Attempting to load IR file: {0}***************", filePath); - Debug.LogMessage(LogEventLevel.Debug, "*************Attempting to load IR file: {0}***************", filePath); + LoadDriver(filePath); - LoadDriver(filePath); - - PrintAvailableCommands(); - }); - } + 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) + /// + /// 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, "***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(); - } + Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", cmd); } + } - /// - /// PressRelease method - /// - /// IR command to send - /// true to press, false to release - /// - public virtual void PressRelease(string command, bool state) + /// + /// 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 { - 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(); + IrPortUid = IrPort.LoadIRDriver(path); + DriverFilepath = path; + StandardIrPulseTime = 200; + DriverIsLoaded = true; + + DriverLoaded.FireUpdate(); } - - /// - /// Pulse method - /// - /// IR command to send - /// time to pulse the command - /// - public virtual void Pulse(string command, ushort time) + 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 == 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); + IrPort.Press(IrPortUid, command); else NoIrCommandError(command); } + else + IrPort.Release(); + } - /// - /// Notifies the console when a bad command is used. - /// - /// command that was not found - protected void NoIrCommandError(string command) + /// + /// 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, "Device {0}: IR Driver {1} does not contain command {2}", - Key, IrPort.IRDriverFileNameByIRDriverId(IrPortUid), command); + 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); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs b/src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs index 821a0c2b..04f14ac9 100644 --- a/src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs @@ -1,113 +1,115 @@ 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 +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 { /// - /// Represents a level control item in a list, which can be used to control volume or mute functionality. + /// Indicates that the item is a level control only /// - 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; } - } - + Level = 1, /// - /// Indicates the type of level control item. + /// Indicates that the item is a mute control only /// - [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, - } - + Mute = 2, + /// + /// Indicates that the item is both a level and mute control + /// + LevelAndMute = Level | Mute, } + + + + + + + diff --git a/src/PepperDash.Essentials.Core/Devices/PduInterfaces.cs b/src/PepperDash.Essentials.Core/Devices/PduInterfaces.cs index 1c0431b5..752ff3ac 100644 --- a/src/PepperDash.Essentials.Core/Devices/PduInterfaces.cs +++ b/src/PepperDash.Essentials.Core/Devices/PduInterfaces.cs @@ -4,33 +4,32 @@ using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Devices +namespace PepperDash.Essentials.Core.Devices; + +/// +/// Interface for any device that is able to control its power and has a configurable reboot time +/// +public interface IHasPowerCycle : IKeyName, IHasPowerControlWithFeedback { /// - /// 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(); - } + /// Delay between power off and power on for reboot + /// + int PowerCycleTimeMs { get;} /// - /// Interface for any device that contains a collection of IHasPowerReboot Devices - /// - public interface IHasControlledPowerOutlets : IKeyName - { - /// - /// Collection of IPduOutlets - /// - ReadOnlyDictionary PduOutlets { 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; } - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/PowerInterfaces.cs b/src/PepperDash.Essentials.Core/Devices/PowerInterfaces.cs index ef0173d5..a4f772d3 100644 --- a/src/PepperDash.Essentials.Core/Devices/PowerInterfaces.cs +++ b/src/PepperDash.Essentials.Core/Devices/PowerInterfaces.cs @@ -1,153 +1,150 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines the contract for IHasBatteryStats +/// +public interface IHasBatteryStats : IKeyName { /// - /// Defines the contract for IHasBatteryStats + /// Gets the BatteryPercentage /// - 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; } - } + int BatteryPercentage { get; } /// - /// Defines the contract for IHasBatteryCharging + /// Gets the BatteryCautionThresholdPercentage /// - public interface IHasBatteryCharging : IHasBatteryStats - { - /// - /// Gets the BatteryIsCharging - /// - BoolFeedback BatteryIsCharging { get; } - } + int BatteryCautionThresholdPercentage { get; } /// - /// Interface for any device that has multiple batteries that can be monitored + /// Gets the BatteryWarningThresholdPercentage /// - public interface IHasBatteries : IKeyName - { - /// - /// Collection of batteries - /// - ReadOnlyDictionary Batteries { get; } - } + int BatteryWarningThresholdPercentage { get; } /// - /// Defines the contract for IHasBatteryStatsExtended + /// Gets the BatteryIsWarningFeedback /// - 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; } - } + BoolFeedback BatteryIsWarningFeedback { get; } /// - /// Defines the contract for IHasPowerCycleWithBattery + /// Gets the BatteryIsCautionFeedback /// - public interface IHasPowerCycleWithBattery : IHasPowerCycle, IHasBatteryStats - { - - } + BoolFeedback BatteryIsCautionFeedback { get; } /// - /// Interface for any device that is able to control it's power and has a configurable reboot time + /// Gets the BatteryIsOkFeedback /// - public interface IHasPowerCycle : IKeyName, IHasPowerControlWithFeedback - { - /// - /// Delay between power off and power on for reboot - /// - int PowerCycleTimeMs { get; } - - /// - /// Reboot outlet - /// - void PowerCycle(); - } + BoolFeedback BatteryIsOkFeedback { get; } /// - /// Interface for any device that contains a collection of IHasPowerReboot Devices + /// Gets the BatteryPercentageFeedback /// - public interface IHasControlledPowerOutlets : IKeyName - { - /// - /// Collection of IPduOutlets - /// - ReadOnlyDictionary PduOutlets { get; } + 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; } -} \ No newline at end of file + /// + /// 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; } +} + +/// +/// Interface for any device that is able to control its power, has a configurable reboot time, and has batteries that can be monitored +/// +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 PDU outlets + /// + ReadOnlyDictionary PduOutlets { get; } + +} diff --git a/src/PepperDash.Essentials.Core/Devices/PresentationDeviceType.cs b/src/PepperDash.Essentials.Core/Devices/PresentationDeviceType.cs index 44474832..ed51738a 100644 --- a/src/PepperDash.Essentials.Core/Devices/PresentationDeviceType.cs +++ b/src/PepperDash.Essentials.Core/Devices/PresentationDeviceType.cs @@ -1,13 +1,4 @@ -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 +namespace PepperDash.Essentials.Core { /// /// Enumeration of PresentationSourceType values @@ -44,4 +35,4 @@ namespace PepperDash.Essentials.Core /// VCR } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Core/Devices/PresetListItem.cs b/src/PepperDash.Essentials.Core/Devices/PresetListItem.cs index 625dcec9..eb9fd026 100644 --- a/src/PepperDash.Essentials.Core/Devices/PresetListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/PresetListItem.cs @@ -1,51 +1,46 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; +using Newtonsoft.Json; using PepperDash.Core; +namespace PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core +/// +/// Represents a PresetListItem +/// + +public class PresetListItem : AudioControlListItemBase { /// - /// Represents a PresetListItem + /// Gets the preset associated with this list item /// - public class PresetListItem : AudioControlListItemBase + [JsonIgnore] + public IKeyName Preset + { - /// - /// Gets the preset associated with this list item - /// - [JsonIgnore] - public IKeyName Preset + get { - get + if (_preset == null) { - 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; + 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; + } + private IKeyName _preset; - /// - /// Gets the name from the device if it implements IKeyName or else returns the Name property - /// - [JsonProperty("preferredName")] - public string PreferredName + /// + /// Gets the name from the device if it implements IKeyName or else returns the Name property + /// + [JsonProperty("preferredName")] + public string PreferredName + { + get { - get - { - if (!string.IsNullOrEmpty(Name)) return Name; + if (!string.IsNullOrEmpty(Name)) return Name; - else return Preset.Name; - } + else return Preset.Name; } } } diff --git a/src/PepperDash.Essentials.Core/Devices/ReconfigurableDevice.cs b/src/PepperDash.Essentials.Core/Devices/ReconfigurableDevice.cs index ccb74a39..a7dc2af2 100644 --- a/src/PepperDash.Essentials.Core/Devices/ReconfigurableDevice.cs +++ b/src/PepperDash.Essentials.Core/Devices/ReconfigurableDevice.cs @@ -12,95 +12,67 @@ using PepperDash.Essentials.Core.Config; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace PepperDash.Essentials.Core.Devices +namespace PepperDash.Essentials.Core.Devices; + +/// +/// +/// +public abstract class ReconfigurableDevice : EssentialsDevice, IReconfigurableDevice { - /// - /// - /// - public abstract class ReconfigurableDevice : EssentialsDevice, IReconfigurableDevice + public event EventHandler ConfigChanged; + + public DeviceConfig Config { get; private set; } + + protected ReconfigurableDevice(DeviceConfig config) + : base(config.Key) { - /// - /// Event fired when the configuration changes - /// - public event EventHandler ConfigChanged; + SetNameHelper(config); - /// - /// 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); - } + Config = config; } /// - /// A ReconfigurableDevice that is also bridgeable + /// Sets the Config, calls CustomSetConfig and fires the ConfigChanged event /// - public abstract class ReconfigurableBridgableDevice : ReconfigurableDevice, IBridgeAdvanced + /// + public void SetConfig(DeviceConfig config) { - /// - /// Constructor - /// - /// config of the device - protected ReconfigurableBridgableDevice(DeviceConfig config) : base(config) - { - } + Config = 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); + 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) + /// + /// + protected virtual void CustomSetConfig(DeviceConfig config) + { + ConfigWriter.UpdateDeviceConfig(config); + } +} + +public abstract class ReconfigurableBridgableDevice : ReconfigurableDevice, IBridgeAdvanced +{ + protected ReconfigurableBridgableDevice(DeviceConfig config) : base(config) + { + } + + public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/SmartObjectBaseTypes.cs b/src/PepperDash.Essentials.Core/Devices/SmartObjectBaseTypes.cs index 55e70de4..1b13203a 100644 --- a/src/PepperDash.Essentials.Core/Devices/SmartObjectBaseTypes.cs +++ b/src/PepperDash.Essentials.Core/Devices/SmartObjectBaseTypes.cs @@ -1,24 +1,23 @@  -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a SmartObjectJoinOffsets +/// +public class SmartObjectJoinOffsets { - /// - /// Represents a SmartObjectJoinOffsets - /// - public class SmartObjectJoinOffsets - { - /// - /// Dpad Join Offset - /// - public const ushort Dpad = 1; + /// + /// Dpad Join Offset + /// + public const ushort Dpad = 1; - /// - /// Numpad Join Offset - /// - public const ushort Numpad = 2; + /// + /// Numpad Join Offset + /// + public const ushort Numpad = 2; - /// - /// PresetList Join Offset - /// - public const ushort PresetList = 6; - } + /// + /// PresetList Join Offset + /// + public const ushort PresetList = 6; } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs index deaeeae3..7ffd711d 100644 --- a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs @@ -4,344 +4,252 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines the type of source list item, which can be a route, off, or other. +/// +public enum eSourceListItemType { + /// + /// Represents a typical route. + /// + Route, + /// + /// Represents an off route. + /// + Off, + /// + /// Represents some other type of route + /// + Other, +} + +/// +/// Represents an item in a source list - can be deserialized into. +/// +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; } + /// /// 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. + /// Returns the source Device for this, if it exists in DeviceManager /// - public enum eSourceListItemType + [JsonIgnore] + public Device SourceDevice { - /// - /// Represents a typical route. - /// - Route, - /// - /// Represents an off route. - /// - Off, - /// - /// Represents some other type of route - /// - Other, + get + { + if (_SourceDevice == null) + _SourceDevice = DeviceManager.GetDeviceForKey(SourceKey) as Device; + return _SourceDevice; + } } - /// - /// 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; } + private Device _SourceDevice; - /// - /// Returns the source Device for this, if it exists in DeviceManager - /// - [JsonIgnore] - public 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 { - get + if (string.IsNullOrEmpty(Name)) { - if (_SourceDevice == null) - _SourceDevice = DeviceManager.GetDeviceForKey(SourceKey) as Device; - return _SourceDevice; + if (SourceDevice == null) + return "---"; + return SourceDevice.Name; } - } - - 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}"; + return Name; } } /// - /// Represents a route in a source list item, which defines the source and destination keys and the type of signal being routed + /// A name that will override the source's name on the UI /// - public class SourceRouteListItem + [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; } + + /// + /// 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() { - /// - /// 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; } + Icon = "Blank"; } /// - /// Defines the valid destination types for SourceListItems in a room + /// Returns a string representation of the SourceListItem, including the SourceKey and Name /// - [Obsolete] - public enum eSourceListItemDestinationTypes + /// A string representation of the SourceListItem + public override string ToString() { - /// - /// 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, + return $"{SourceKey}:{Name}"; } -} \ No newline at end of file +} + +/// +/// 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; } +} + diff --git a/src/PepperDash.Essentials.Core/Devices/VolumeDeviceChangeEventArgs.cs b/src/PepperDash.Essentials.Core/Devices/VolumeDeviceChangeEventArgs.cs index ae2895db..7aeac9ee 100644 --- a/src/PepperDash.Essentials.Core/Devices/VolumeDeviceChangeEventArgs.cs +++ b/src/PepperDash.Essentials.Core/Devices/VolumeDeviceChangeEventArgs.cs @@ -1,14 +1,7 @@ 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; -namespace PepperDash.Essentials.Core -{ /// /// /// @@ -58,4 +51,3 @@ namespace PepperDash.Essentials.Core /// DidChange } -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/eSourceListItemDestinationTypes.cs b/src/PepperDash.Essentials.Core/Devices/eSourceListItemDestinationTypes.cs new file mode 100644 index 00000000..7b9e9b35 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Devices/eSourceListItemDestinationTypes.cs @@ -0,0 +1,94 @@ +using System; + +namespace PepperDash.Essentials.Core; + +/// +/// Defines the eSourceListItemDestinationTypes enumeration, which represents the various destination types for source list items in a room control system. +/// This enumeration is marked as obsolete, indicating that it may be removed in future versions and should not be used in new development. +/// Each member of the enumeration corresponds to a specific type of display or audio output commonly found in room control systems, +/// such as default displays, program audio, codec content, and auxiliary displays. +/// +[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, +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Ethernet/EthernetStatistics.cs b/src/PepperDash.Essentials.Core/Ethernet/EthernetStatistics.cs index 0f5c2863..c5097d07 100644 --- a/src/PepperDash.Essentials.Core/Ethernet/EthernetStatistics.cs +++ b/src/PepperDash.Essentials.Core/Ethernet/EthernetStatistics.cs @@ -6,52 +6,51 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Ethernet +namespace PepperDash.Essentials.Core.Ethernet; + +/// +/// Ethernet settings feedbacks +/// +public static class EthernetSettings { /// - /// Ethernet settings feedbacks + /// Link active feedback /// - public static class EthernetSettings - { - /// - /// Link active feedback - /// - public static readonly BoolFeedback LinkActive = new BoolFeedback("LinkActive", - () => true); + 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"); + /// + /// 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)); + /// + /// 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)); + /// + /// 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)); + /// + /// 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)); - } + /// + /// Default Gateway feedback + /// + public static readonly StringFeedback DefaultGateway0 = new StringFeedback("DefaultGateway0", + () => CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0)); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Extensions/IpAddressExtensions.cs b/src/PepperDash.Essentials.Core/Extensions/IpAddressExtensions.cs index 35ec1b8a..6da2211a 100644 --- a/src/PepperDash.Essentials.Core/Extensions/IpAddressExtensions.cs +++ b/src/PepperDash.Essentials.Core/Extensions/IpAddressExtensions.cs @@ -5,82 +5,81 @@ using System.Net; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +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 { /// - /// Extensions for IPAddress to provide additional functionality such as getting broadcast address, network address, and checking if two addresses are in the same subnet. + /// Get the broadcast address for a given IP address and subnet mask. /// - public static class IPAddressExtensions + /// 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) { - /// - /// 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++) { - 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); + 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) + /// + /// 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++) { - 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); + 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); + /// + /// 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); - } + return network1.Equals(network2); } } diff --git a/src/PepperDash.Essentials.Core/Extensions/JsonExtensions.cs b/src/PepperDash.Essentials.Core/Extensions/JsonExtensions.cs index 74697525..1a6bbb6b 100644 --- a/src/PepperDash.Essentials.Core/Extensions/JsonExtensions.cs +++ b/src/PepperDash.Essentials.Core/Extensions/JsonExtensions.cs @@ -1,52 +1,44 @@ - - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Newtonsoft.Json; +using System.Collections.Generic; using Newtonsoft.Json.Linq; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// JsonExtensions class +/// +public static class JsonExtensions { /// - /// JsonExtensions class + /// FindTokens method /// - public static class JsonExtensions + /// token for the container + /// name of the token to find + /// list of matching tokens + public static List FindTokens(this JToken containerToken, string name) { - /// - /// 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; - } + List matches = new List(); + FindTokens(containerToken, name, matches); + return matches; + } - private static void FindTokens(JToken containerToken, string name, List matches) + private static void FindTokens(JToken containerToken, string name, List matches) + { + if (containerToken.Type == JTokenType.Object) { - if (containerToken.Type == JTokenType.Object) + foreach (JProperty child in containerToken.Children()) { - foreach (JProperty child in containerToken.Children()) + if (child.Name == name) { - if (child.Name == name) - { - matches.Add(child.Value); - } - FindTokens(child.Value, name, matches); + matches.Add(child.Value); } + FindTokens(child.Value, name, matches); } - else if (containerToken.Type == JTokenType.Array) + } + else if (containerToken.Type == JTokenType.Array) + { + foreach (JToken child in containerToken.Children()) { - foreach (JToken child in containerToken.Children()) - { - FindTokens(child, name, matches); - } + FindTokens(child, name, matches); } } } diff --git a/src/PepperDash.Essentials.Core/Extensions/StringExtensions.cs b/src/PepperDash.Essentials.Core/Extensions/StringExtensions.cs index 9dbb6244..bdbe69ad 100644 --- a/src/PepperDash.Essentials.Core/Extensions/StringExtensions.cs +++ b/src/PepperDash.Essentials.Core/Extensions/StringExtensions.cs @@ -5,77 +5,66 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// StringExtensions class +/// +public static class StringExtensions { /// - /// StringExtensions class + /// Returns null if a string is empty or made of only whitespace characters, otherwise returns the string /// - public static class StringExtensions + /// 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) { - /// - /// 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); - } - + 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); + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs index f1a0923e..6672532f 100644 --- a/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs @@ -2,29 +2,28 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines a class that is capable of loading device types +/// +public interface IDeviceFactory { /// - /// Defines the contract for IDeviceFactory + /// Gets the type of the factory associated with the current instance. /// - public interface IDeviceFactory - { - /// - /// Gets the type of the factory associated with the current instance. - /// - Type FactoryType { get; } + Type FactoryType { get; } - /// - /// Gets a list of type names associated with the current plugin. - /// - List TypeNames { 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); - } + /// + /// 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); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Factory/IProcessorExtensionDeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/IProcessorExtensionDeviceFactory.cs index 57870721..b0d56508 100644 --- a/src/PepperDash.Essentials.Core/Factory/IProcessorExtensionDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Factory/IProcessorExtensionDeviceFactory.cs @@ -4,16 +4,17 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +/// +/// Defines the contract for IProcessorExtensionDeviceFactory +/// +public interface IProcessorExtensionDeviceFactory { /// - /// Defines the contract for IProcessorExtensionDeviceFactory + /// Loads all the extension factories to the ProcessorExtensionDeviceFactory /// - public interface IProcessorExtensionDeviceFactory - { - /// - /// Loads all the extension factories to the ProcessorExtensionDeviceFactory - /// - void LoadFactories(); - } + void LoadFactories(); } + diff --git a/src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs index 1d9f41e1..eb02f3e5 100644 --- a/src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs @@ -7,8 +7,8 @@ using System; using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Represents a ProcessorExtensionDeviceFactory @@ -164,8 +164,6 @@ namespace PepperDash.Essentials.Core Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.InnerException.StackTrace); return null; } - } - } } diff --git a/src/PepperDash.Essentials.Core/Factory/ReadyEventArgs.cs b/src/PepperDash.Essentials.Core/Factory/ReadyEventArgs.cs index 544ef5cc..23fa1d1a 100644 --- a/src/PepperDash.Essentials.Core/Factory/ReadyEventArgs.cs +++ b/src/PepperDash.Essentials.Core/Factory/ReadyEventArgs.cs @@ -1,45 +1,39 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using PepperDash.Essentials.Core; +namespace PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core + +/// +/// Represents a IsReadyEventArgs +/// +public class IsReadyEventArgs : EventArgs { /// - /// Represents a IsReadyEventArgs + /// Gets or sets the IsReady /// - 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; - } - } + public bool IsReady { get; set; } /// - /// Defines the contract for IHasReady + /// Constructor /// - public interface IHasReady + /// indicates if the object is ready + public IsReadyEventArgs(bool data) { - /// - /// Fires when the IsReady property changes - /// - event EventHandler IsReadyEvent; - - /// - /// indicates whether the object is ready - /// - bool IsReady { get; } + 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; } +} diff --git a/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedback.cs b/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedback.cs index ea222b7f..3aa75e22 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedback.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedback.cs @@ -5,195 +5,165 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// A Feedback whose output is derived from the return value of a provided Func. +/// +public class BoolFeedback : Feedback { /// - /// A Feedback whose output is derived from the return value of a provided Func. + /// Returns the current value of the feedback, derived from the ValueFunc. The ValueFunc is + /// evaluated whenever FireUpdate() is called /// - public class BoolFeedback : Feedback + public override bool BoolValue { get { return _BoolValue; } } + bool _BoolValue; + + /// + /// Fake value to be used in test mode + /// + public bool TestValue { get; private set; } + + /// + /// Func that evaluates on FireUpdate + /// + 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 + public BoolFeedback(Func valueFunc) + : this(null, valueFunc) { - /// - /// 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; } + /// + /// 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; + } - /// - /// Gets or sets the ValueFunc - /// - public Func ValueFunc { get; private set; } + public void SetValueFunc(Func newFunc) + { + ValueFunc = newFunc; + } - 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) + public override void FireUpdate() + { + bool newValue = InTestMode ? TestValue : ValueFunc.Invoke(); + if (newValue != _BoolValue) { - } - - /// - /// 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; + _BoolValue = newValue; + LinkedInputSigs.ForEach(s => UpdateSig(s)); + LinkedComplementInputSigs.ForEach(s => UpdateComplementSig(s)); + OnOutputChange(newValue); } } + /// + /// Links an input sig + /// + /// + public void LinkInputSig(BoolInputSig sig) + { + LinkedInputSigs.Add(sig); + UpdateSig(sig); + } + + /// + /// Unlinks an inputs sig + /// + /// + 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 + /// + /// + 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); + } + + /// + /// + /// + /// + public void UnlinkCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) + { + LinkedCrestronFeedbacks.Remove(feedback); + } + + public override string ToString() + { + return (InTestMode ? "TEST -- " : "") + BoolValue.ToString(); + } + + /// + /// Puts this in test mode, sets the test value and fires an update. + /// + /// + 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; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackOneShot.cs b/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackOneShot.cs index 6b0b39b8..d0d0083e 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackOneShot.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackOneShot.cs @@ -1,29 +1,24 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; +using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { - /// - /// Represents a BoolFeedbackPulse - /// + /// + /// Represents a BoolFeedbackPulse + /// public class BoolFeedbackPulse { - /// - /// Gets or sets the TimeoutMs - /// + /// + /// Gets or sets the TimeoutMs + /// public uint TimeoutMs { get; set; } - /// - /// Gets or sets the CanRetrigger - /// + /// + /// Gets or sets the CanRetrigger + /// public bool CanRetrigger { get; set; } - /// - /// Gets or sets the Feedback - /// + /// + /// Gets or sets the Feedback + /// public BoolFeedback Feedback { get; private set; } CTimer Timer; @@ -68,12 +63,12 @@ namespace PepperDash.Essentials.Core Timer.Reset(TimeoutMs); } - /// - /// Cancel method - /// + /// + /// Cancel method + /// public void Cancel() { - if(Timer != null) + if (Timer != null) Timer.Reset(0); } } diff --git a/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackPulseExtender.cs b/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackPulseExtender.cs index 3a9dccde..87c6e9d7 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackPulseExtender.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackPulseExtender.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core -{ +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. @@ -81,5 +81,4 @@ namespace PepperDash.Essentials.Core Feedback.FireUpdate(); Timer = null; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/BoolOutputLogicals.cs b/src/PepperDash.Essentials.Core/Feedbacks/BoolOutputLogicals.cs index 901b80dd..323a9be1 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/BoolOutputLogicals.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/BoolOutputLogicals.cs @@ -5,8 +5,8 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Abstract base class for BoolOutputLogicals @@ -98,7 +98,7 @@ namespace PepperDash.Essentials.Core public void ClearOutputs() { OutputsIn.Clear(); - Evaluate(); + Evaluate(); } /// @@ -190,5 +190,4 @@ namespace PepperDash.Essentials.Core ComputedValue = newValue; Output.FireUpdate(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/FeedbackBase.cs b/src/PepperDash.Essentials.Core/Feedbacks/FeedbackBase.cs index 0c756ace..e54fc864 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/FeedbackBase.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/FeedbackBase.cs @@ -1,10 +1,5 @@ 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 @@ -120,4 +115,4 @@ namespace PepperDash.Essentials.Core if (OutputChange != null) OutputChange(this, new FeedbackEventArgs(value)); } } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Core/Feedbacks/FeedbackCollection.cs b/src/PepperDash.Essentials.Core/Feedbacks/FeedbackCollection.cs index ed7517da..32b1abfb 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/FeedbackCollection.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/FeedbackCollection.cs @@ -4,22 +4,21 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Basically a List , with an indexer to find feedbacks by key name +/// +public class FeedbackCollection : List where T : Feedback { /// - /// Basically a List , with an indexer to find feedbacks by key name + /// Case-insensitive port lookup linked to feedbacks' keys /// - public class FeedbackCollection : List where T : Feedback + public T this[string key] { - /// - /// Case-insensitive port lookup linked to feedbacks' keys - /// - public T this[string key] + get { - get - { - return this.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); - } + return this.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/FeedbackEventArgs.cs b/src/PepperDash.Essentials.Core/Feedbacks/FeedbackEventArgs.cs index e22e9366..d2c1a815 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/FeedbackEventArgs.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/FeedbackEventArgs.cs @@ -4,93 +4,96 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a FeedbackEventArgs +/// +public class FeedbackEventArgs : EventArgs { /// - /// Represents a FeedbackEventArgs + /// Gets or sets the BoolValue /// - public class FeedbackEventArgs : EventArgs + 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 { - /// - /// 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 { - 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; + return (ushort)IntValue; } } /// - /// Enumeration of eFeedbackEventType values + /// Gets or sets the StringValue /// - public enum eFeedbackEventType + 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) { - /// - /// Boolean type feedback event - /// - TypeBool, - - /// - /// Integer type feedback event - /// - TypeInt, - - /// - /// String type feedback event - /// - TypeString + BoolValue = value; + Type = eFeedbackEventType.TypeBool; } -} \ No newline at end of file + + /// + /// 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 +} + + + + diff --git a/src/PepperDash.Essentials.Core/Feedbacks/IntFeedback.cs b/src/PepperDash.Essentials.Core/Feedbacks/IntFeedback.cs index 4dd0424b..1cf7a3bd 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/IntFeedback.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/IntFeedback.cs @@ -5,132 +5,98 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class IntFeedback : Feedback { + public override int IntValue { get { return _IntValue; } } // ValueFunc.Invoke(); } } + int _IntValue; + public ushort UShortValue { get { return (ushort)_IntValue; } } + + //public override eCueType Type { get { return eCueType.Int; } } + + public int TestValue { get; private set; } + /// - /// Represents a IntFeedback + /// Func evaluated on FireUpdate /// - public class IntFeedback : Feedback + 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 + public IntFeedback(Func valueFunc) + : this(null, valueFunc) { - /// - /// 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; } } + /// + /// 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; + } - /// - /// Gets or sets the TestValue - /// - public int TestValue { get; private set; } + public void SetValueFunc(Func newFunc) + { + ValueFunc = newFunc; + } - /// - /// 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) + public override void FireUpdate() + { + var newValue = InTestMode ? TestValue : ValueFunc.Invoke(); + if (newValue != _IntValue) { - } - - /// - /// 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; + _IntValue = newValue; + LinkedInputSigs.ForEach(s => UpdateSig(s)); + OnOutputChange(newValue); } } + + public void LinkInputSig(UShortInputSig sig) + { + LinkedInputSigs.Add(sig); + UpdateSig(sig); + } + + public void UnlinkInputSig(UShortInputSig sig) + { + LinkedInputSigs.Remove(sig); + } + + public override string ToString() + { + return (InTestMode ? "TEST -- " : "") + IntValue.ToString(); + } + + /// + /// Puts this in test mode, sets the test value and fires an update. + /// + /// + public void SetTestValue(int value) + { + TestValue = value; + InTestMode = true; + FireUpdate(); + } + + void UpdateSig(UShortInputSig sig) + { + sig.UShortValue = UShortValue; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/SerialFeedback.cs b/src/PepperDash.Essentials.Core/Feedbacks/SerialFeedback.cs index 1bde5a08..6fe0be62 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/SerialFeedback.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/SerialFeedback.cs @@ -5,112 +5,81 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core +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 { + public override string SerialValue { get { return _SerialValue; } } + string _SerialValue; + + //public override eCueType Type { get { return eCueType.Serial; } } + /// - /// 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. + /// Used in testing. Set/Clear functions /// - public class SerialFeedback : Feedback + public string TestValue { get; private set; } + + List LinkedInputSigs = new List(); + + public SerialFeedback() { - /// - /// Gets the SerialValue - /// - public override string SerialValue { get { return _SerialValue; } } - string _SerialValue; + } - //public override eCueType Type { get { return eCueType.Serial; } } + public SerialFeedback(string key) + : base(key) + { + } - /// - /// Gets or sets the TestValue - /// - public string TestValue { get; private set; } + public override void FireUpdate() + { + throw new NotImplementedException("This feedback type does not use Funcs"); + } - List LinkedInputSigs = new List(); + public void FireUpdate(string newValue) + { + _SerialValue = newValue; + LinkedInputSigs.ForEach(s => UpdateSig(s, newValue)); + OnOutputChange(newValue); + } - /// - /// Constructor - /// - [Obsolete("use constructor with Key parameter. This constructor will be removed in a future version")] - public SerialFeedback() - { - } + public void LinkInputSig(StringInputSig sig) + { + LinkedInputSigs.Add(sig); + UpdateSig(sig); + } - /// - /// Constructor with Key parameter - /// - /// Key to find this Feedback - public SerialFeedback(string key) - : base(key) - { - } + public void UnlinkInputSig(StringInputSig sig) + { + LinkedInputSigs.Remove(sig); + } - /// - /// FireUpdate method - /// - /// - public override void FireUpdate() - { - throw new NotImplementedException("This feedback type does not use Funcs"); - } + public override string ToString() + { + return (InTestMode ? "TEST -- " : "") + SerialValue; + } - /// - /// FireUpdate method - /// - public void FireUpdate(string newValue) - { - _SerialValue = newValue; - LinkedInputSigs.ForEach(s => UpdateSig(s, newValue)); - OnOutputChange(newValue); - } + /// + /// Puts this in test mode, sets the test value and fires an update. + /// + /// + public void SetTestValue(string value) + { + TestValue = value; + InTestMode = true; + FireUpdate(TestValue); + } - /// - /// LinkInputSig method - /// - public void LinkInputSig(StringInputSig sig) - { - LinkedInputSigs.Add(sig); - UpdateSig(sig); - } + void UpdateSig(StringInputSig sig) + { + sig.StringValue = _SerialValue; + } - /// - /// 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; - } + void UpdateSig(StringInputSig sig, string value) + { + sig.StringValue = value; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/StringFeedback.cs b/src/PepperDash.Essentials.Core/Feedbacks/StringFeedback.cs index 4c419903..2eb18414 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/StringFeedback.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/StringFeedback.cs @@ -5,126 +5,98 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +public class StringFeedback : Feedback { + public override string StringValue { get { return _StringValue; } } // ValueFunc.Invoke(); } } + string _StringValue; /// - /// Represents a StringFeedback + /// Used in testing. Set/Clear functions /// - public class StringFeedback : Feedback + public string TestValue { get; private set; } + + /// + /// Evaluated on FireUpdate + /// + 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 + public StringFeedback(Func valueFunc) + : this(null, valueFunc) { - /// - /// 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; } + /// + /// 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; + } - /// - /// Gets or sets the ValueFunc - /// - public Func ValueFunc { get; private set; } - List LinkedInputSigs = new List(); + public void SetValueFunc(Func newFunc) + { + ValueFunc = newFunc; + } - /// - /// 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) + public override void FireUpdate() + { + var newValue = InTestMode ? TestValue : ValueFunc.Invoke(); + if (newValue != _StringValue) { - } - - /// - /// 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; + _StringValue = newValue; + LinkedInputSigs.ForEach(s => UpdateSig(s)); + OnOutputChange(newValue); } } + + public void LinkInputSig(StringInputSig sig) + { + LinkedInputSigs.Add(sig); + UpdateSig(sig); + } + + public void UnlinkInputSig(StringInputSig sig) + { + LinkedInputSigs.Remove(sig); + } + + public override string ToString() + { + return (InTestMode ? "TEST -- " : "") + StringValue; + } + + /// + /// Puts this in test mode, sets the test value and fires an update. + /// + /// + public void SetTestValue(string value) + { + TestValue = value; + InTestMode = true; + FireUpdate(); + } + + void UpdateSig(StringInputSig sig) + { + sig.StringValue = _StringValue; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/File/FileIO.cs b/src/PepperDash.Essentials.Core/File/FileIO.cs index df1c0750..25a6d87c 100644 --- a/src/PepperDash.Essentials.Core/File/FileIO.cs +++ b/src/PepperDash.Essentials.Core/File/FileIO.cs @@ -34,43 +34,42 @@ namespace PepperDash.Essentials.Core /// /// /// - /// - /// 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; - } - } + 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 full file info from a path/filename, can include wildcards. + /// + /// + /// + 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; + } + } /// @@ -78,9 +77,9 @@ namespace PepperDash.Essentials.Core /// /// /// - /// - /// ReadDataFromFile method - /// + /// + /// ReadDataFromFile method + /// public static string ReadDataFromFile(string fileName) { try @@ -94,15 +93,15 @@ namespace PepperDash.Essentials.Core } } - /// - /// Get the data with fileInfo object - /// - /// - /// - /// - /// ReadDataFromFile method - /// - public static string ReadDataFromFile(FileInfo file) + /// + /// Get the data with fileInfo object + /// + /// + /// + /// + /// ReadDataFromFile method + /// + public static string ReadDataFromFile(FileInfo file) { try { @@ -129,7 +128,7 @@ namespace PepperDash.Essentials.Core Debug.LogMessage(LogEventLevel.Information, "FileIO Unable to enter FileLock"); return ""; } - + } catch (Exception e) { @@ -145,9 +144,9 @@ namespace PepperDash.Essentials.Core } - /// - /// ReadDataFromFileASync method - /// + /// + /// ReadDataFromFileASync method + /// public static void ReadDataFromFileASync(string fileName) { try @@ -160,9 +159,9 @@ namespace PepperDash.Essentials.Core } } - /// - /// ReadDataFromFileASync method - /// + /// + /// ReadDataFromFileASync method + /// public static void ReadDataFromFileASync(FileInfo file) { try @@ -230,7 +229,7 @@ namespace PepperDash.Essentials.Core public static void WriteDataToFile(string data, string filePath) { Thread _WriteFileThread; - _WriteFileThread = new Thread((O) => _WriteFileMethod(data, Global.FilePathPrefix + "/" + filePath), null, Thread.eThreadStartOptions.CreateSuspended); + _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"); @@ -246,7 +245,7 @@ namespace PepperDash.Essentials.Core if (fileLock.TryEnter()) { - using (StreamWriter sw = new StreamWriter(filePath)) + using (StreamWriter sw = new StreamWriter(filePath)) { sw.Write(data); sw.Flush(); @@ -277,16 +276,16 @@ namespace PepperDash.Essentials.Core /// /// /// - /// - /// FileIoUnitTest method - /// + /// + /// 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); @@ -301,9 +300,9 @@ namespace PepperDash.Essentials.Core } } - /// - /// Represents a FileEventArgs - /// + /// + /// Represents a FileEventArgs + /// public class FileEventArgs { /// @@ -311,9 +310,9 @@ namespace PepperDash.Essentials.Core /// /// public FileEventArgs(string data) { Data = data; } - /// - /// Gets or sets the Data - /// + /// + /// Gets or sets the Data + /// public string Data { get; private set; } // readonly } diff --git a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs index ba638623..d31f4cdf 100644 --- a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs @@ -7,227 +7,227 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core.Bridges; -namespace PepperDash.Essentials.Core.Fusion +namespace PepperDash.Essentials.Core.Fusion; + +/// +/// Represents a EssentialsHuddleSpaceRoomFusionRoomJoinMap +/// +public class EssentialsHuddleSpaceRoomFusionRoomJoinMap : JoinMapBaseAdvanced { + + // Processor Attributes /// - /// Represents a EssentialsHuddleSpaceRoomFusionRoomJoinMap + /// Processor IP 1 /// - public class EssentialsHuddleSpaceRoomFusionRoomJoinMap : JoinMapBaseAdvanced + [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)) { - // 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 }); + /// + /// 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) + { + } +} - /// - /// 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) - { - } - } -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Fusion/FusionCustomPropertiesBridge.cs b/src/PepperDash.Essentials.Core/Fusion/FusionCustomPropertiesBridge.cs index 12f5d7e4..f4493fa5 100644 --- a/src/PepperDash.Essentials.Core/Fusion/FusionCustomPropertiesBridge.cs +++ b/src/PepperDash.Essentials.Core/Fusion/FusionCustomPropertiesBridge.cs @@ -8,129 +8,89 @@ using PepperDash.Core; using PepperDash.Essentials.Core.Devices; using Serilog.Events; -namespace PepperDash.Essentials.Core.Fusion +namespace PepperDash.Essentials.Core.Fusion; + +/// +/// Handles mapping Fusion Custom Property values to system properties +/// +public class FusionCustomPropertiesBridge { + /// - /// Handles mapping Fusion Custom Property values to system properties + /// Evaluates the room info and custom properties from Fusion and updates the system properties aa needed /// - public class FusionCustomPropertiesBridge + /// The room associated with this Fusion instance + /// The room information from Fusion + /// + public void EvaluateRoomInfo(IEssentialsRoom room, RoomInformation roomInfo, bool useFusionRoomName) { + var reconfigurableDevices = DeviceManager.AllDevices.Where(d => d is ReconfigurableDevice); - /// - /// 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) + foreach (var device in reconfigurableDevices) { - try + // Get the current device config so new values can be overwritten over existing + var deviceConfig = (device as ReconfigurableDevice).Config; + + if (device is IEssentialsRoom) { - 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); - } + // 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; } - catch (Exception e) + + if (device is RoomOnToDefaultSourceWhenOccupied) { - Debug.LogError("FusionCustomPropetiesBridge: Exception mapping properties for {roomKey}: {message}", room.Key, e.Message); - Debug.LogDebug(e, "Stack Trace: "); + 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 as ReconfigurableDevice).SetConfig(deviceConfig); } + + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Fusion/FusionEventHandlers.cs b/src/PepperDash.Essentials.Core/Fusion/FusionEventHandlers.cs index 6f374237..c6f766ea 100644 --- a/src/PepperDash.Essentials.Core/Fusion/FusionEventHandlers.cs +++ b/src/PepperDash.Essentials.Core/Fusion/FusionEventHandlers.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; + namespace PepperDash.Essentials.Core.Fusion { diff --git a/src/PepperDash.Essentials.Core/Fusion/FusionProcessorQueries.cs b/src/PepperDash.Essentials.Core/Fusion/FusionProcessorQueries.cs index 86ed62f3..aefe37ac 100644 --- a/src/PepperDash.Essentials.Core/Fusion/FusionProcessorQueries.cs +++ b/src/PepperDash.Essentials.Core/Fusion/FusionProcessorQueries.cs @@ -1,73 +1,67 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Fusion +namespace PepperDash.Essentials.Core.Fusion; + +/// +/// When created, runs progcomments on every slot and stores the program names in a list +/// +public class ProcessorProgReg { /// - /// When created, runs progcomments on every slot and stores the program names in a list + /// Gets the processor program registry /// - public class ProcessorProgReg + /// + public static Dictionary GetProcessorProgReg() { - //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++) { - 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 { - string response = null; - var success = CrestronConsole.SendControlSystemCommand("progcomments:" + i, ref response); - var item = new ProcessorProgramItem(); - if (!success) - item.Name = "Error: PROGCOMMENTS failed"; + if (response.ToLower().Contains("bad or incomplete")) + item.Name = ""; 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")) { - 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(); - } + 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; + programs[i] = item; + Debug.LogMessage(LogEventLevel.Debug, "Program {0}: {1}", i, item.Name); } + return programs; } +} +/// +/// Represents a ProcessorProgramItem +/// +public class ProcessorProgramItem +{ /// - /// Represents a ProcessorProgramItem + /// Gets or sets the Exists /// - public class ProcessorProgramItem - { - /// - /// Gets or sets the Exists - /// - public bool Exists { get; set; } - /// - /// Gets or sets the Name - /// - public string Name { get; set; } - } -} \ No newline at end of file + public bool Exists { get; set; } + /// + /// Gets or sets the Name + /// + public string Name { get; set; } +} diff --git a/src/PepperDash.Essentials.Core/Fusion/FusionRviDataClasses.cs b/src/PepperDash.Essentials.Core/Fusion/FusionRviDataClasses.cs index cef4926f..ba53564a 100644 --- a/src/PepperDash.Essentials.Core/Fusion/FusionRviDataClasses.cs +++ b/src/PepperDash.Essentials.Core/Fusion/FusionRviDataClasses.cs @@ -8,828 +8,492 @@ using Crestron.SimplSharpPro.Fusion; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Fusion +namespace PepperDash.Essentials.Core.Fusion; + +// Helper Classes for GUIDs + +/// +/// Stores GUIDs to be written to a file in NVRAM +/// +public class FusionRoomGuids { - // Helper Classes for GUIDs + public string RoomName { get; set; } + public uint IpId { get; set; } + public string RoomGuid { get; set; } + public FusionOccupancySensorAsset OccupancyAsset { get; set; } + public Dictionary StaticAssets { get; set; } - /// - /// Stores GUIDs to be written to a file in NVRAM - /// - public class FusionRoomGuids + public FusionRoomGuids() { - /// - /// Gets or sets the RoomName - /// - public string RoomName { get; set; } + StaticAssets = new Dictionary(); + OccupancyAsset = new FusionOccupancySensorAsset(); + } - /// - /// Gets or sets the IpId - /// - public uint IpId { get; set; } + public FusionRoomGuids(string roomName, uint ipId, string roomGuid, Dictionary staticAssets) + { + RoomName = roomName; + IpId = ipId; + RoomGuid = roomGuid; - /// - /// Gets or sets the RoomGuid - /// - public string RoomGuid { get; set; } + StaticAssets = staticAssets; + OccupancyAsset = new FusionOccupancySensorAsset(); + } - /// - /// 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; - } + public FusionRoomGuids(string roomName, uint ipId, string roomGuid, Dictionary staticAssets, FusionOccupancySensorAsset occAsset) + { + RoomName = roomName; + IpId = ipId; + RoomGuid = roomGuid; + StaticAssets = staticAssets; + OccupancyAsset = occAsset; } /// - /// Represents a FusionOccupancySensorAsset + /// Generates a new room GUID prefixed by the program slot number and NIC MAC address /// - public class FusionOccupancySensorAsset + /// + /// + public string GenerateNewRoomGuid(uint progSlot, string mac) { - // SlotNumber fixed at 4 + Guid roomGuid = Guid.NewGuid(); - /// - /// 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; } + return string.Format("{0}-{1}-{2}", progSlot, mac, roomGuid.ToString()); + } - /// - /// Default constructor - /// - public FusionOccupancySensorAsset() + + /// + /// 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 + /// + /// + /// + public static uint GetNextAvailableAssetNumber(FusionRoom room) + { + uint slotNum = 0; + + foreach (var item in room.UserConfigurableAssetDetails) { + if(item.Number > slotNum) + slotNum = item.Number; } - /// - /// FusionOccupancySensorAsset constructor - /// - /// asset type - public FusionOccupancySensorAsset(eAssetType type) + if (slotNum < 5) { - Type = type; + slotNum = 5; + } + else + slotNum = slotNum + 1; + Debug.LogMessage(LogEventLevel.Verbose, "#Next available fusion asset number is: {0}", slotNum); + + return slotNum; + } + +} + +public class FusionOccupancySensorAsset +{ + // SlotNumber fixed at 4 + + public uint SlotNumber { get { return 4; } } + public string Name { get { return "Occupancy Sensor"; } } + public eAssetType Type { get; set; } + public string InstanceId { get; set; } + + public FusionOccupancySensorAsset() + { + } + + public FusionOccupancySensorAsset(eAssetType type) + { + Type = type; + + InstanceId = Guid.NewGuid().ToString(); + } +} + +public class FusionAsset +{ + public uint SlotNumber { get; set; } + public string Name { get; set; } + public string Type { get; set; } + public string InstanceId { get;set; } + + public FusionAsset() + { + + } + + 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; + } } +} + +//*************************************************************************************************** + +public class RoomSchedule +{ + public List Meetings { get; set; } + + public RoomSchedule() + { + Meetings = new List(); + } +} + +//**************************************************************************************************** +// Helper Classes for XML API + +/// +/// Data needed to request the local time from the Fusion server +/// +public class LocalTimeRequest +{ + 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")] + public string RequestID { get; set; } + //[XmlElement(ElementName = "RoomID")] + public string RoomID { get; set; } + //[XmlElement(ElementName = "Start")] + public DateTime Start { get; set; } + //[XmlElement(ElementName = "HourSpan")] + public double HourSpan { get; set; } + + public RequestSchedule(string requestID, string roomID) + { + RequestID = requestID; + RoomID = roomID; + Start = DateTime.Now; + HourSpan = 24; + } +} + + +//[XmlRoot(ElementName = "RequestAction")] +public class RequestAction +{ + //[XmlElement(ElementName = "RequestID")] + public string RequestID { get; set; } + //[XmlElement(ElementName = "RoomID")] + public string RoomID { get; set; } + //[XmlElement(ElementName = "ActionID")] + public string ActionID { get; set; } + //[XmlElement(ElementName = "Parameters")] + public List Parameters { get; set; } + + public RequestAction(string roomID, string actionID, List parameters) + { + RoomID = roomID; + ActionID = actionID; + Parameters = parameters; + } +} + +//[XmlRoot(ElementName = "ActionResponse")] +public class ActionResponse +{ + //[XmlElement(ElementName = "RequestID")] + public string RequestID { get; set; } + //[XmlElement(ElementName = "ActionID")] + public string ActionID { get; set; } + //[XmlElement(ElementName = "Parameters")] + public List Parameters { get; set; } +} + +//[XmlRoot(ElementName = "Parameter")] +public class Parameter +{ + //[XmlAttribute(AttributeName = "ID")] + public string ID { get; set; } + //[XmlAttribute(AttributeName = "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")] + public string RequestID { get; set; } + //[XmlElement(ElementName = "RoomID")] + public string RoomID { get; set; } + //[XmlElement(ElementName = "RoomName")] + public string RoomName { get; set; } + //[XmlElement("Event")] + public List Events { get; set; } + + public ScheduleResponse() + { + Events = new List(); + } +} + +//[XmlRoot(ElementName = "Event")] +public class Event +{ + //[XmlElement(ElementName = "MeetingID")] + public string MeetingID { get; set; } + //[XmlElement(ElementName = "RVMeetingID")] + public string RVMeetingID { get; set; } + //[XmlElement(ElementName = "Recurring")] + public string Recurring { get; set; } + //[XmlElement(ElementName = "InstanceID")] + public string InstanceID { get; set; } + //[XmlElement(ElementName = "dtStart")] + public DateTime dtStart { get; set; } + //[XmlElement(ElementName = "dtEnd")] + public DateTime dtEnd { get; set; } + //[XmlElement(ElementName = "Organizer")] + public string Organizer { get; set; } + //[XmlElement(ElementName = "Attendees")] + public Attendees Attendees { get; set; } + //[XmlElement(ElementName = "Resources")] + public Resources Resources { get; set; } + //[XmlElement(ElementName = "IsEvent")] + public string IsEvent { get; set; } + //[XmlElement(ElementName = "IsRoomViewMeeting")] + public string IsRoomViewMeeting { get; set; } + //[XmlElement(ElementName = "IsPrivate")] + public string IsPrivate { get; set; } + //[XmlElement(ElementName = "IsExchangePrivate")] + public string IsExchangePrivate { get; set; } + //[XmlElement(ElementName = "MeetingTypes")] + public MeetingTypes MeetingTypes { get; set; } + //[XmlElement(ElementName = "ParticipantCode")] + public string ParticipantCode { get; set; } + //[XmlElement(ElementName = "PhoneNo")] + public string PhoneNo { get; set; } + //[XmlElement(ElementName = "WelcomeMsg")] + public string WelcomeMsg { get; set; } + //[XmlElement(ElementName = "Subject")] + public string Subject { get; set; } + //[XmlElement(ElementName = "LiveMeeting")] + public LiveMeeting LiveMeeting { get; set; } + //[XmlElement(ElementName = "ShareDocPath")] + public string ShareDocPath { get; set; } + //[XmlElement(ElementName = "HaveAttendees")] + public string HaveAttendees { get; set; } + //[XmlElement(ElementName = "HaveResources")] + public string HaveResources { get; set; } /// - /// Represents a FusionAsset + /// Gets the duration of the meeting /// - public class FusionAsset + public string DurationInMinutes { - /// - /// 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() + get { + string duration; - } - - /// - /// 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)) + var timeSpan = dtEnd.Subtract(dtStart); + int hours = timeSpan.Hours; + double minutes = timeSpan.Minutes; + double roundedMinutes = Math.Round(minutes); + if (hours > 0) { - InstanceId = Guid.NewGuid().ToString(); + duration = string.Format("{0} hours {1} minutes", hours, roundedMinutes); } else { - InstanceId = instanceId; + duration = string.Format("{0} minutes", roundedMinutes); } + + return duration; } } - //*************************************************************************************************** - /// - /// Represents a RoomSchedule + /// Gets the remaining time in the meeting. Returns null if the meeting is not currently in progress. /// - public class RoomSchedule + public string RemainingTime { - /// - /// Gets or sets the Meetings - /// - public List Meetings { get; set; } - - /// - /// RoomSchedule constructor - /// - public RoomSchedule() + get { - Meetings = new List(); - } - } + var now = DateTime.Now; - //**************************************************************************************************** - // Helper Classes for XML API + string remainingTime; - /// - /// 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 + if (GetInProgress()) { - string duration; - - var timeSpan = dtEnd.Subtract(dtStart); + var timeSpan = dtEnd.Subtract(now); 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); + remainingTime = string.Format("{0} hours {1} minutes", hours, roundedMinutes); } else { - duration = string.Format("{0} minutes", roundedMinutes); + remainingTime = 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; + return remainingTime; } else - return false; + return null; + } + + } + + /// + /// Indicates that the meeting is in progress + /// + public bool isInProgress + { + get + { + return GetInProgress(); } } - //[XmlRoot(ElementName = "Resources")] /// - /// Represents a Resources + /// Determines if the meeting is in progress /// - public class Resources + /// Returns true if in progress + bool GetInProgress() { - //[XmlElement(ElementName = "Rooms")] - /// - /// Gets or sets the Rooms - /// - public Rooms Rooms { get; set; } - } + var now = DateTime.Now; - //[XmlRoot(ElementName = "Rooms")] - /// - /// Represents a Rooms - /// - public class Rooms - { - //[XmlElement(ElementName = "Room")] - /// - /// Gets or sets the Room - /// - public List Room { get; set; } + if (now > dtStart && now < dtEnd) + { + return true; + } + else + return false; } +} - //[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 = "Resources")] +public class Resources +{ + //[XmlElement(ElementName = "Rooms")] + public Rooms Rooms { 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 = "Rooms")] +public class Rooms +{ + //[XmlElement(ElementName = "Room")] + public List Room { 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 = "Room")] +public class Room +{ + //[XmlElement(ElementName = "Name")] + public string Name { get; set; } + //[XmlElement(ElementName = "ID")] + public string ID { get; set; } + //[XmlElement(ElementName = "MPType")] + public string MPType { 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 = "Attendees")] +public class Attendees +{ + //[XmlElement(ElementName = "Required")] + public Required Required { get; set; } + //[XmlElement(ElementName = "Optional")] + public Optional Optional { 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 = "Required")] +public class Required +{ + //[XmlElement(ElementName = "Attendee")] + public List Attendee { 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 = "Optional")] +public class Optional +{ + //[XmlElement(ElementName = "Attendee")] + public List Attendee { 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 = "MeetingType")] +public class MeetingType +{ + //[XmlAttribute(AttributeName = "ID")] + public string ID { get; set; } + //[XmlAttribute(AttributeName = "Value")] + public string Value { get; set; } +} - //[XmlRoot(ElementName = "LiveMeetingURL")] - /// - /// Represents a LiveMeetingURL - /// - public class LiveMeetingURL - { - //[XmlElement(ElementName = "LiveMeeting")] - /// - /// Gets or sets the LiveMeeting - /// - public LiveMeeting LiveMeeting { get; set; } - } +//[XmlRoot(ElementName = "MeetingTypes")] +public class MeetingTypes +{ + //[XmlElement(ElementName = "MeetingType")] + public List MeetingType { get; set; } +} + +//[XmlRoot(ElementName = "LiveMeeting")] +public class LiveMeeting +{ + //[XmlElement(ElementName = "URL")] + public string URL { get; set; } + //[XmlElement(ElementName = "ID")] + public string ID { get; set; } + //[XmlElement(ElementName = "Key")] + public string Key { get; set; } + //[XmlElement(ElementName = "Subject")] + public string Subject { get; set; } +} + +//[XmlRoot(ElementName = "LiveMeetingURL")] +public class LiveMeetingURL +{ + //[XmlElement(ElementName = "LiveMeeting")] + public LiveMeeting LiveMeeting { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Global/EthernetAdapterInfo.cs b/src/PepperDash.Essentials.Core/Global/EthernetAdapterInfo.cs index 6565c6de..68701639 100644 --- a/src/PepperDash.Essentials.Core/Global/EthernetAdapterInfo.cs +++ b/src/PepperDash.Essentials.Core/Global/EthernetAdapterInfo.cs @@ -4,56 +4,56 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +/// +/// Represents a EthernetAdapterInfo +/// +public class EthernetAdapterInfo { /// - /// Represents a EthernetAdapterInfo + /// Gets or sets the Type /// - 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; } - } -} \ No newline at end of file + 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; } +} diff --git a/src/PepperDash.Essentials.Core/Global/Global.cs b/src/PepperDash.Essentials.Core/Global/Global.cs index d1ed3efb..5eeb5e96 100644 --- a/src/PepperDash.Essentials.Core/Global/Global.cs +++ b/src/PepperDash.Essentials.Core/Global/Global.cs @@ -4,7 +4,6 @@ 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; @@ -12,9 +11,6 @@ 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; @@ -57,126 +53,126 @@ namespace PepperDash.Essentials.Core public static IFormatProvider Culture = CultureInfo.InvariantCulture; - /// - /// True when the processor type is a DMPS variant - /// - public static bool ControlSystemIsDmpsType + /// + /// True when the processor type is a DMPS variant + /// + public static bool ControlSystemIsDmpsType + { + get { - get + if(ControlSystem.SystemControl != null) { - if(ControlSystem.SystemControl != null) + if(ControlSystem.SystemControl.SystemControlType > 0) { - if(ControlSystem.SystemControl.SystemControlType > 0) - { - return true; - } - } - return false; + return true; + } } + return false; } + } - /// - /// True when the processor type is a DMPS 4K variant - /// - public static bool ControlSystemIsDmps4kType + /// + /// True when the processor type is a DMPS 4K variant + /// + public static bool ControlSystemIsDmps4kType + { + get { - get + if(ControlSystem.SystemControl != null) { - 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) { - 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; + return true; + } } + return false; } + } - /// - /// True when the processor type is a DMPS 4K 200/300/250/350 variant - /// - public static bool ControlSystemIsDmps4k3xxType + /// + /// True when the processor type is a DMPS 4K 200/300/250/350 variant + /// + public static bool ControlSystemIsDmps4k3xxType + { + get { - get + if(ControlSystem.SystemControl != null) { - 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) { - 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; + 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 + /// + /// The file path prefix to the applciation directory + /// + public static string ApplicationDirectoryPathPrefix + { + get { - get - { - return Crestron.SimplSharp.CrestronIO.Directory.GetApplicationDirectory(); - } + return Crestron.SimplSharp.CrestronIO.Directory.GetApplicationDirectory(); } + } - /// - /// Returns the directory separator character based on the running OS - /// - public static char DirectorySeparator + /// + /// Returns the directory separator character based on the running OS + /// + public static char DirectorySeparator + { + get { - get - { - return System.IO.Path.DirectorySeparatorChar; - } + return System.IO.Path.DirectorySeparatorChar; } + } - /// - /// Wildcarded config file name for global reference - /// - public const string ConfigFileName = "*configurationFile*.json"; + /// + /// Wildcarded config file name for global reference + /// + public const string ConfigFileName = "*configurationFile*.json"; - /// - /// Sets the file path prefix - /// - /// - public static void SetFilePathPrefix(string prefix) + /// + /// 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 { - FilePathPrefix = prefix; - Debug.LogMessage(LogEventLevel.Information, "File Path Prefix set to '{0}'", FilePathPrefix); + return _AssemblyVersion; } - - static string _AssemblyVersion; - - /// - /// Gets the Assembly Version of Essentials - /// - /// The Assembly Version at Runtime - public static string AssemblyVersion + private set { - get - { - return _AssemblyVersion; - } - private set - { - _AssemblyVersion = value; - } + _AssemblyVersion = value; } + } /// /// Sets the Assembly version to the version of the Essentials Library @@ -201,18 +197,18 @@ namespace PepperDash.Essentials.Core { if (Regex.Match(AssemblyVersion, @"^(\d*).(\d*).(\d*).*").Groups[1].Value == "0") { - Debug.LogMessage(LogEventLevel.Verbose, "Running Local Build. Bypassing Dependency Check."); - return true; + 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); + "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); + Debug.LogMessage(LogEventLevel.Verbose, "Comparing running version '{0}' to minimum versions '{1}'", AssemblyVersion, developmentVersions); var versionMatch = developmentVersions.FirstOrDefault(x => x == AssemblyVersion); @@ -222,83 +218,83 @@ namespace PepperDash.Essentials.Core return false; } - Debug.LogMessage(LogEventLevel.Verbose, "Essentials Build {0} matches list of development builds", AssemblyVersion); + 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) + /// + /// 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.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."); + 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 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; - */ } + + 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() { @@ -310,17 +306,17 @@ namespace PepperDash.Essentials.Core return; } - try - { - CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture("en"); - CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture("en"); - } - catch (CultureNotFoundException) - { - // If specific culture fails, fall back to invariant - CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; - CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; - } + try + { + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture("en"); + CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture("en"); + } + catch (CultureNotFoundException) + { + // If specific culture fails, fall back to invariant + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; + CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; + } } } diff --git a/src/PepperDash.Essentials.Core/Global/JobTimer.cs b/src/PepperDash.Essentials.Core/Global/JobTimer.cs index 55814368..0d75a972 100644 --- a/src/PepperDash.Essentials.Core/Global/JobTimer.cs +++ b/src/PepperDash.Essentials.Core/Global/JobTimer.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using Crestron.SimplSharp; +using System.Timers; namespace PepperDash.Essentials.Core { @@ -11,7 +10,7 @@ namespace PepperDash.Essentials.Core /// public static class JobTimer { - static CTimer MinuteTimer; + static Timer MinuteTimer; static List Items = new List(); @@ -42,7 +41,9 @@ namespace PepperDash.Essentials.Core { if (Items.Count > 0 && MinuteTimer == null) { - MinuteTimer = new CTimer(o => MinuteTimerCallback(), null, 60000, 60000); + MinuteTimer = new Timer(60000); + MinuteTimer.Elapsed += (sender, e) => MinuteTimerCallback(); + MinuteTimer.Start(); } } diff --git a/src/PepperDash.Essentials.Core/Global/Scheduler.cs b/src/PepperDash.Essentials.Core/Global/Scheduler.cs index c946b67d..ff1773fe 100644 --- a/src/PepperDash.Essentials.Core/Global/Scheduler.cs +++ b/src/PepperDash.Essentials.Core/Global/Scheduler.cs @@ -1,103 +1,100 @@ using System; using System.Collections.Generic; -using System.Linq; using Crestron.SimplSharp; 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 +namespace PepperDash.Essentials.Core; + +/// +/// Global Scheduler for the system +/// +public static class Scheduler { - /// - /// Global Scheduler for the system - /// - public static class Scheduler + private static readonly Dictionary EventGroups = new Dictionary(); + + static Scheduler() { - private static readonly Dictionary EventGroups = new Dictionary(); + CrestronConsole.AddNewConsoleCommand(DeleteEventGroup, "DeleteEventGroup", "Deletes the event group by key", ConsoleAccessLevelEnum.AccessOperator); - static Scheduler() + 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)) { - 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(); + EventGroups.Remove(groupName); - 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); + 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; } - static void ListAllEventGroups(string command) + var group = EventGroups[groupName]; + + if (group != null) { - CrestronConsole.ConsoleCommandResponse("Event Groups:"); - foreach (var group in EventGroups) - { - CrestronConsole.ConsoleCommandResponse($"{group.Key}"); - } + 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; } - static void ListAllEventsForGroup(string args) + foreach (var evt in group.ScheduledEvents) { - 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( + CrestronConsole.ConsoleCommandResponse( $@" ****Event key {evt.Key}**** Event state: {evt.Value.EventState} @@ -107,224 +104,223 @@ 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 + /// Adds the event group to the global list /// - public static class SchedulerUtilities + /// + /// + /// AddEventGroup method + /// + public static void AddEventGroup(ScheduledEventGroup eventGroup) { - /// - /// 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) + // 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) { - 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; + 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); - /// - /// CheckEventTimeForMatch method - /// - public static bool CheckEventTimeForMatch(ScheduledEvent evnt, DateTime time) - { - return evnt.DateAndTime.Hour == time.Hour && evnt.DateAndTime.Minute == time.Minute; - } + return isMatch; + } - /// - /// 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) + /// + /// 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 { - try + if (group == null) { - 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(); - } - + Debug.LogMessage(LogEventLevel.Information, "Unable to create event. Group is null", null, null); + return; } - catch (Exception e) + var scheduledEvent = new ScheduledEvent(config.Key, group) { + Acknowledgeable = config.Acknowledgeable, + Persistent = config.Persistent + }; - Debug.LogMessage(LogEventLevel.Error, "Error creating scheduled event: {0}", null, e); + 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(); + } + } - - private static ScheduledEventCommon.eWeekDays ConvertDayOfWeek(DateTime eventTime) + catch (Exception e) { - 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)); + Debug.LogMessage(LogEventLevel.Error, "Error creating scheduled event: {0}", null, e); } } -} \ No newline at end of file + + 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)); + } +} diff --git a/src/PepperDash.Essentials.Core/InUseTracking/IInUseTracking.cs b/src/PepperDash.Essentials.Core/InUseTracking/IInUseTracking.cs index 59ea87b3..440b14bd 100644 --- a/src/PepperDash.Essentials.Core/InUseTracking/IInUseTracking.cs +++ b/src/PepperDash.Essentials.Core/InUseTracking/IInUseTracking.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Defines a class that uses an InUseTracker /// @@ -15,5 +15,4 @@ namespace PepperDash.Essentials.Core /// Gets the InUseTracker /// InUseTracking InUseTracker { get; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/InUseTracking/InUseTracking.cs b/src/PepperDash.Essentials.Core/InUseTracking/InUseTracking.cs index c0fcdbf6..247e8548 100644 --- a/src/PepperDash.Essentials.Core/InUseTracking/InUseTracking.cs +++ b/src/PepperDash.Essentials.Core/InUseTracking/InUseTracking.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Provides in use tracking. Objects can register with this. InUseFeedback can provide /// events when usage changes. @@ -113,5 +113,4 @@ namespace PepperDash.Essentials.Core // Tracker = tracker; // EventType = eventType; // } - //} -} \ No newline at end of file + //} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Interfaces/ILogStrings.cs b/src/PepperDash.Essentials.Core/Interfaces/ILogStrings.cs index d55194fd..78446c6f 100644 --- a/src/PepperDash.Essentials.Core/Interfaces/ILogStrings.cs +++ b/src/PepperDash.Essentials.Core/Interfaces/ILogStrings.cs @@ -5,16 +5,15 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Interfaces +namespace PepperDash.Essentials.Core.Interfaces; + +/// +/// Defines the contract for ILogStrings +/// +public interface ILogStrings : IKeyed { - /// - /// Defines the contract for ILogStrings - /// - public interface ILogStrings : IKeyed - { - /// - /// Defines a class that is capable of logging a string - /// - void SendToLog(IKeyed device, string logMessage); - } + /// + /// Defines a class that is capable of logging a string + /// + void SendToLog(IKeyed device, string logMessage); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Interfaces/ILogStringsWithLevel.cs b/src/PepperDash.Essentials.Core/Interfaces/ILogStringsWithLevel.cs index bb835919..b9d61df1 100644 --- a/src/PepperDash.Essentials.Core/Interfaces/ILogStringsWithLevel.cs +++ b/src/PepperDash.Essentials.Core/Interfaces/ILogStringsWithLevel.cs @@ -5,17 +5,15 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Interfaces -{ - /// - /// Defines the contract for ILogStringsWithLevel - /// - 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); - } +namespace PepperDash.Essentials.Core.Interfaces; +/// +/// Defines the contract for ILogStringsWithLevel +/// +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); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/JoinMaps/JoinMapBase.cs b/src/PepperDash.Essentials.Core/JoinMaps/JoinMapBase.cs index d2e7d036..9cd6776e 100644 --- a/src/PepperDash.Essentials.Core/JoinMaps/JoinMapBase.cs +++ b/src/PepperDash.Essentials.Core/JoinMaps/JoinMapBase.cs @@ -15,648 +15,526 @@ using PepperDash.Essentials.Core.Config; using Newtonsoft.Json; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public static class JoinMapHelper { /// - /// JoinMapHelper class + /// Attempts to get the serialized join map from config /// - public static class JoinMapHelper + /// + /// + public static string GetSerializedJoinMapForDevice(string joinMapKey) { - /// - /// 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 + /// + /// + /// + 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; - 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 (!ConfigReader.ConfigObject.JoinMaps.ContainsKey(joinMapKey)) { - 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); + 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 +{ + protected uint JoinOffset; + /// - /// Base class for join maps + /// The collection of joins and associated metadata /// - public abstract class JoinMapBaseAdvanced + public Dictionary Joins { get; private set; } + + protected JoinMapBaseAdvanced(uint joinStart) { - /// - /// The join offset - /// - protected uint JoinOffset; + Joins = new Dictionary(); - /// - /// The collection of joins and associated metadata - /// - public Dictionary Joins { get; private set; } + JoinOffset = joinStart - 1; + } - /// - /// Constructor - /// - /// join start offset - protected JoinMapBaseAdvanced(uint joinStart) + protected JoinMapBaseAdvanced(uint joinStart, Type type):this(joinStart) + { + AddJoins(type); + } + + 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) { - Joins = new Dictionary(); + var childClass = Convert.ChangeType(this, type, null); - JoinOffset = joinStart - 1; - } + //this here is JoinMapBaseAdvanced, not the child class. JoinMapBaseAdvanced has no fields. - /// - /// 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) + if (!(field.GetValue(childClass) is JoinDataComplete value)) { - 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); + Debug.LogMessage(LogEventLevel.Information, "Unable to cast base class to {0}", type.Name); + continue; } + value.SetJoinOffset(JoinOffset); - if (Debug.Level > 0) - { - PrintJoinMapInfo(); - } - } + var joinName = value.GetNameAttribute(field); - /// - /// PrintJoinMapInfo method - /// - public void PrintJoinMapInfo() - { - var sb = JoinmapStringBuilder(); + if (string.IsNullOrEmpty(joinName)) continue; - 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; + Joins.Add(joinName, value); } - static StringBuilder AppendJoinList(List> joins) + if (Debug.Level > 0) { - 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 + /// Prints the join information to console /// - [Flags] - public enum eJoinCapabilities + public void PrintJoinMapInfo() { - /// - /// No capabilities - /// - None = 0, + var sb = JoinmapStringBuilder(); - /// - /// 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, + CrestronConsole.ConsoleCommandResponse(sb.ToString()); } - /// - /// Enumeration of eJoinType values - /// - [Flags] - public enum eJoinType + private StringBuilder JoinmapStringBuilder() { - /// - /// No join type - /// - None = 0, + var sb = new StringBuilder(); - /// - /// Digital join - /// - Digital = 1, + var lineEnding = "\r\n"; - /// - /// Analog join - /// - Analog = 2, + var digitals = + Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Digital)) + .ToDictionary(j => j.Key, j => j.Value); - /// - /// Serial join - /// - Serial = 4, + var analogs = Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Analog)) + .ToDictionary(j => j.Key, j => j.Value); - /// - /// Digital and Analog join - /// - DigitalAnalog = Digital | Analog, + var serials = + Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Serial)) + .ToDictionary(j => j.Key, j => j.Value); - /// - /// Digital and Serial join - /// - DigitalSerial = Digital | Serial, + 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); - /// - /// 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; } + // 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 - /// - /// Gets or sets the JoinCapabilities - /// - [JsonProperty("joinCapabilities")] - public eJoinCapabilities JoinCapabilities { get; set; } + var digitalSb = AppendJoinList(GetSortedJoins(digitals)); + digitalSb.Append($"## Analogs{lineEnding}"); + digitalSb.Append(lineEnding); + + var analogSb = AppendJoinList(GetSortedJoins(analogs)); + analogSb.Append($"## Serials{lineEnding}"); + analogSb.Append(lineEnding); - /// - /// Gets or sets the ValidValues - /// - [JsonProperty("validValues")] - public string[] ValidValues { get; set; } + + var serialSb = AppendJoinList(GetSortedJoins(serials)); + sb.EnsureCapacity(sb.Length + digitalSb.Length + analogSb.Length + serialSb.Length); + sb.Append(digitalSb).Append(analogSb).Append(serialSb); + return sb; } /// - /// Data describing the join. Can be overridden from configuratino + /// Prints the join information to console /// - public class JoinData + public void MarkdownJoinMapInfo(string deviceKey, string bridgeKey) { - /// - /// Join number (based on join offset value) - /// - [JsonProperty("joinNumber")] - public uint JoinNumber { get; set; } + var pluginType = GetType().Name; - /// - /// 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; } + CrestronConsole.ConsoleCommandResponse("{0}:\n", pluginType); + + + + WriteJoinmapMarkdown(JoinmapStringBuilder(), pluginType, bridgeKey, deviceKey); - /// - /// 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 static void WriteJoinmapMarkdown(StringBuilder stringBuilder, string pluginType, string bridgeKey, string deviceKey) { - private uint _joinOffset; + var fileName = string.Format("{0}{1}{2}__{3}__{4}.md", Global.FilePathPrefix, "joinMaps/", pluginType, bridgeKey, deviceKey); - 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) + using (var sw = new StreamWriter(fileName)) { - _data = data; - Metadata = metadata; + sw.WriteLine(stringBuilder.ToString()); + CrestronConsole.ConsoleCommandResponse("Joinmap Readme generated and written to {0}", fileName); } - /// - /// GetMarkdownFormattedData method - /// - /// formatter to use - /// length of the description - /// - public string GetMarkdownFormattedData(string stringFormatter, int descriptionLen) + } + + /// + /// 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; + } - //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; + /// + /// Attempts to find the matching key for the custom join and if found overwrites the default JoinData with the custom + /// + /// + public void SetCustomJoinData(Dictionary joinData) + { + foreach (var customJoinData in joinData) + { + JoinDataComplete join; - //Track which one failed, if it did - const string placeholder = "unknown"; - var dataArray = new Dictionary + if (!Joins.TryGetValue(customJoinData.Key, out join)) { - {"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"]); - + Debug.LogMessage(LogEventLevel.Verbose, "No matching key found in join map for: '{0}'", customJoinData.Key); + continue; } - catch (Exception e) + + if (join != null) { - //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"]); + join.SetCustomJoinData(customJoinData.Value); } } + PrintJoinMapInfo(); + } - /// - /// Sets the join offset value - /// - /// - public void SetJoinOffset(uint joinOffset) + ///// + ///// Returns the join number for the join with the specified key + ///// + ///// + ///// + //public uint GetJoinForKey(string key) + //{ + // return Joins.ContainsKey(key) ? Joins[key].JoinNumber : 0; + //} + + + ///// + ///// 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 +{ + None = 0, + ToSIMPL = 1, + FromSIMPL = 2, + ToFromSIMPL = ToSIMPL | FromSIMPL, + ToFusion = 4, + FromFusion = 8, + ToFromFusion = ToFusion | FromFusion, +} + +[Flags] +public enum eJoinType +{ + None = 0, + Digital = 1, + Analog = 2, + Serial = 4, + DigitalAnalog = Digital | Analog, + DigitalSerial = Digital | Serial, + AnalogSerial = Analog | Serial, + DigitalAnalogSerial = Digital | Analog | Serial, +} + +/// +/// Metadata describing the join +/// +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; } } + /// + /// Signal type(s) + /// + [JsonProperty("joinType")] + public eJoinType JoinType { get; set; } + /// + /// Indicates whether the join is read and/or write + /// + [JsonProperty("joinCapabilities")] + public eJoinCapabilities JoinCapabilities { get; set; } + /// + /// Indicates a set of valid values (particularly if this translates to an enum + /// + [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; } + /// + /// Fusion Attribute Name (optional) + /// + [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; + public JoinMetadata Metadata { get; set; } + /// + /// To store some future information as you please + /// + public object UserObject { get; private set; } + + public JoinDataComplete(JoinData data, JoinMetadata metadata) + { + _data = data; + Metadata = metadata; + } + + public string GetMarkdownFormattedData(string stringFormatter, int descriptionLen) + { + + //Fixed Width Headers + var joinNumberLen = string.Format("Join Number").Length; + var joinSpanLen = string.Format("Join Span").Length; + var typeLen = string.Format("AnalogDigitalSerial").Length; + var capabilitiesLen = string.Format("ToFromFusion").Length; + + //Track which one failed, if it did + const string placeholder = "unknown"; + var dataArray = new Dictionary { - _joinOffset = joinOffset; + {"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"]); + } - - /// - /// The join number (including the offset) - /// - public uint JoinNumber + catch (Exception e) { - 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; + //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"]); } } - /// - /// Represents a JoinNameAttribute + /// Sets the join offset value /// - [AttributeUsage(AttributeTargets.All)] - public class JoinNameAttribute : Attribute + /// + public void SetJoinOffset(uint joinOffset) { - private string _Name; + _joinOffset = joinOffset; + } - /// - /// Constructor - /// - /// name of the attribute - public JoinNameAttribute(string name) - { - Debug.LogMessage(LogEventLevel.Verbose, "Setting Attribute Name: {0}",null, name); - _Name = name; - } + /// + /// The join number (including the offset) + /// + public uint JoinNumber + { + get { return _data.JoinNumber+ _joinOffset; } + set { _data.JoinNumber = value; } + } - /// - /// Gets the Name - /// - public string Name - { - get { return _Name; } - } + public uint JoinSpan + { + get { return _data.JoinSpan; } + } + + public string AttributeName + { + get { return _data.AttributeName; } + } + + public void SetCustomJoinData(JoinData customJoinData) + { + _data = customJoinData; + } + + 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; + } +} + + + +[AttributeUsage(AttributeTargets.All)] +public class JoinNameAttribute : Attribute +{ + private string _Name; + + public JoinNameAttribute(string name) + { + Debug.LogMessage(LogEventLevel.Verbose, "Setting Attribute Name: {0}",null, name); + _Name = name; + } + + public string Name + { + get { return _Name; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/License/EssentialsLicenseManager.cs b/src/PepperDash.Essentials.Core/License/EssentialsLicenseManager.cs index ded7f699..9a6d2434 100644 --- a/src/PepperDash.Essentials.Core/License/EssentialsLicenseManager.cs +++ b/src/PepperDash.Essentials.Core/License/EssentialsLicenseManager.cs @@ -11,104 +11,103 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.License +namespace PepperDash.Essentials.License; + +/// +/// Abstract base class for License Managers +/// +public abstract class LicenseManager { /// - /// Abstract base class for License Managers + /// Gets or sets the LicenseIsValid /// - public abstract class LicenseManager + 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() { - /// - /// 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(); + CrestronConsole.AddNewConsoleCommand( + s => CrestronConsole.ConsoleCommandResponse(GetStatusString()), + "licensestatus", "shows license and related data", + ConsoleAccessLevelEnum.AccessOperator); } /// - /// Represents a MockEssentialsLicenseManager + /// Gets the status string for console command /// - public class MockEssentialsLicenseManager : LicenseManager + protected abstract string GetStatusString(); +} + +/// +/// Represents a MockEssentialsLicenseManager +/// +public class MockEssentialsLicenseManager : LicenseManager +{ + /// + /// Returns the singleton mock license manager for this app + /// + public static MockEssentialsLicenseManager Manager { - /// - /// Returns the singleton mock license manager for this app - /// - public static MockEssentialsLicenseManager Manager + get { - 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"); + 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"); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Lighting/Lighting Interfaces.cs b/src/PepperDash.Essentials.Core/Lighting/Lighting Interfaces.cs index 642ca6f8..dfc6cd28 100644 --- a/src/PepperDash.Essentials.Core/Lighting/Lighting Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Lighting/Lighting Interfaces.cs @@ -1,118 +1,118 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core.Lighting +namespace PepperDash.Essentials.Core.Lighting; + + +/// +/// Defines the contract for ILightingScenes +/// +public interface ILightingScenes { /// - /// Defines the contract for ILightingScenes + /// Fires when the lighting scene changes /// - 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; } - - } + event EventHandler LightingSceneChange; /// - /// Defines the contract for ILightingScenesDynamic + /// Gets the list of LightingScenes /// - public interface ILightingScenesDynamic : ILightingScenes - { - /// - /// Fires when the lighting scenes are updated - /// - event EventHandler LightingScenesUpdated; - } + List LightingScenes { get; } /// - /// Defines the contract for ILightingMasterRaiseLower + /// Selects the given LightingScene /// - public interface ILightingMasterRaiseLower - { - /// - /// Raises the master level - /// - void MasterRaise(); - - /// - /// Lowers the master level - /// - void MasterLower(); - - /// - /// Stops raising or lowering the master level - /// - void MasterRaiseLowerStop(); - } + /// scene to select + void SelectScene(LightingScene scene); /// - /// Defines the contract for ILightingLoad + /// Gets the currently selected LightingScene /// - public interface ILightingLoad - { - /// - /// Sets the load level - /// - /// level to set - void SetLoadLevel(int level); + LightingScene CurrentLightingScene { get; } - /// - /// Raises the load level - /// - void Raise(); +} - /// - /// Lowers the load level - /// - void Lower(); +/// +/// Defines the contract for ILightingScenesDynamic +/// +public interface ILightingScenesDynamic : ILightingScenes +{ + /// + /// Fires when the lighting scenes are updated + /// + event EventHandler LightingScenesUpdated; +} - /// - /// feedback of the current load level - /// - IntFeedback LoadLevelFeedback { get; } - - /// - /// feedback of whether the load is on - /// - BoolFeedback LoadIsOnFeedback { get; } - } +/// +/// Defines the contract for ILightingMasterRaiseLower +/// +public interface ILightingMasterRaiseLower +{ + /// + /// Raises the master level + /// + void MasterRaise(); /// - /// Represents a LightingSceneChangeEventArgs + /// Lowers the master level /// - public class LightingSceneChangeEventArgs : EventArgs + 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) { - /// - /// 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; - } + CurrentLightingScene = scene; } +} -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyController.cs b/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyController.cs index a15e0dc4..29cd4e3c 100644 --- a/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyController.cs +++ b/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyController.cs @@ -11,286 +11,247 @@ 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; +namespace PepperDash.Essentials.Core.Privacy; - bool initialized; +/// +/// 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 + public bool EnableLeds + { + get { - get - { - return _enableLeds; - } - set - { - _enableLeds = value; + return _enableLeds; + } + set + { + _enableLeds = value; - if (initialized) + if (initialized) + { + if (value) { - if (value) - { - CheckPrivacyMode(); - SetLedStates(); - } - else - TurnOffAllLeds(); + CheckPrivacyMode(); + SetLedStates(); } + else + TurnOffAllLeds(); } } - bool _enableLeds; + } + + bool _enableLeds; - /// - /// Gets or sets the Inputs - /// - public List Inputs { get; private set; } + public List Inputs { get; private set; } - /// - /// Gets or sets the RedLedRelay - /// - public GenericRelayDevice RedLedRelay { get; private set; } - bool _redLedRelayState; + public GenericRelayDevice RedLedRelay { get; private set; } + bool _redLedRelayState; - /// - /// Gets or sets the GreenLedRelay - /// - public GenericRelayDevice GreenLedRelay { get; private set; } - bool _greenLedRelayState; + public GenericRelayDevice GreenLedRelay { get; private set; } + bool _greenLedRelayState; - /// - /// Gets or sets the PrivacyDevice - /// - public IPrivacy PrivacyDevice { get; private set; } + 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) + public MicrophonePrivacyController(string key, MicrophonePrivacyControllerConfig config) : + base(key) + { + Config = config; + + Inputs = new List(); + } + + public override bool CustomActivate() + { + foreach (var i in Config.Inputs) { - Config = config; + var input = DeviceManager.GetDeviceForKey(i.DeviceKey) as IDigitalInput; - Inputs = new List(); + if(input != null) + AddInput(input); } - /// - /// CustomActivate method - /// - /// - public override bool CustomActivate() - { - foreach (var i in Config.Inputs) - { - var input = DeviceManager.GetDeviceForKey(i.DeviceKey) as IDigitalInput; + var greenLed = DeviceManager.GetDeviceForKey(Config.GreenLedRelay.DeviceKey) as GenericRelayDevice; - if(input != null) - AddInput(input); - } + if (greenLed != null) + GreenLedRelay = greenLed; + else + Debug.LogMessage(LogEventLevel.Information, this, "Unable to add Green LED device"); - var greenLed = DeviceManager.GetDeviceForKey(Config.GreenLedRelay.DeviceKey) as GenericRelayDevice; + var redLed = DeviceManager.GetDeviceForKey(Config.RedLedRelay.DeviceKey) as GenericRelayDevice; - if (greenLed != null) - GreenLedRelay = greenLed; - else - Debug.LogMessage(LogEventLevel.Information, this, "Unable to add Green LED device"); + if (redLed != null) + RedLedRelay = redLed; + else + Debug.LogMessage(LogEventLevel.Information, this, "Unable to add Red LED device"); - var redLed = DeviceManager.GetDeviceForKey(Config.RedLedRelay.DeviceKey) as GenericRelayDevice; + AddPostActivationAction(() => { + PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange -= PrivacyModeIsOnFeedback_OutputChange; + PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; + }); - if (redLed != null) - RedLedRelay = redLed; - else - Debug.LogMessage(LogEventLevel.Information, this, "Unable to add Red LED device"); + initialized = true; - AddPostActivationAction(() => { - PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange -= PrivacyModeIsOnFeedback_OutputChange; - PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; - }); + return base.CustomActivate(); + } - initialized = true; + #region Overrides of Device - return base.CustomActivate(); - } + public override void Initialize() + { + CheckPrivacyMode(); + } - #region Overrides of Device + #endregion - /// - /// Initialize method - /// - /// - public override void Initialize() - { - CheckPrivacyMode(); - } + public void SetPrivacyDevice(IPrivacy privacyDevice) + { + PrivacyDevice = privacyDevice; + } - #endregion - - /// - /// SetPrivacyDevice method - /// - public void SetPrivacyDevice(IPrivacy privacyDevice) - { - PrivacyDevice = privacyDevice; - } - - void PrivacyModeIsOnFeedback_OutputChange(object sender, EventArgs e) - { + void PrivacyModeIsOnFeedback_OutputChange(object sender, EventArgs e) + { Debug.LogMessage(LogEventLevel.Debug, this, "Privacy mode change: {0}", sender as BoolFeedback); - CheckPrivacyMode(); - } + CheckPrivacyMode(); + } - void CheckPrivacyMode() + void CheckPrivacyMode() + { + if (PrivacyDevice != null) { - if (PrivacyDevice != null) - { - var privacyState = PrivacyDevice.PrivacyModeIsOnFeedback.BoolValue; + 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(); - } + if (privacyState) + TurnOnRedLeds(); else - TurnOffAllLeds(); + TurnOnGreenLeds(); } + } - /// - /// Turns off all LEDs - /// - void TurnOffAllLeds() - { - _redLedRelayState = false; - _greenLedRelayState = false; + void AddInput(IDigitalInput input) + { + Inputs.Add(input); - SetRelayStates(); - } + input.InputStateFeedback.OutputChange += InputStateFeedback_OutputChange; + } - void SetRelayStates() - { - if (RedLedRelay != null) - { - if (_redLedRelayState) - RedLedRelay.CloseRelay(); - else - RedLedRelay.OpenRelay(); - } + void RemoveInput(IDigitalInput input) + { + var tempInput = Inputs.FirstOrDefault(i => i.Equals(input)); - if(GreenLedRelay != null) - { - if (_greenLedRelayState) - GreenLedRelay.CloseRelay(); - else - GreenLedRelay.OpenRelay(); - } - } + if (tempInput != null) + tempInput.InputStateFeedback.OutputChange -= InputStateFeedback_OutputChange; + + Inputs.Remove(input); + } + + void SetRedLedRelay(GenericRelayDevice relay) + { + RedLedRelay = relay; + } + + void SetGreenLedRelay(GenericRelayDevice relay) + { + GreenLedRelay = relay; } /// - /// Represents a MicrophonePrivacyControllerFactory + /// Check the state of the input change and handle accordingly /// - public class MicrophonePrivacyControllerFactory : EssentialsDeviceFactory + /// + /// + void InputStateFeedback_OutputChange(object sender, EventArgs e) { - /// - /// 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); - } + 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(); + } + } +} + +public class MicrophonePrivacyControllerFactory : EssentialsDeviceFactory +{ + public MicrophonePrivacyControllerFactory() + { + TypeNames = new List() { "microphoneprivacycontroller" }; + } + + 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); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyControllerConfig.cs b/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyControllerConfig.cs index 902b51ed..d5df4531 100644 --- a/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyControllerConfig.cs +++ b/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyControllerConfig.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Essentials.Core.CrestronIO; +using System.Collections.Generic; namespace PepperDash.Essentials.Core.Privacy { diff --git a/src/PepperDash.Essentials.Core/Monitoring/CrestronGenericBaseCommunicationMonitor.cs b/src/PepperDash.Essentials.Core/Monitoring/CrestronGenericBaseCommunicationMonitor.cs index dc9406a3..2fce0783 100644 --- a/src/PepperDash.Essentials.Core/Monitoring/CrestronGenericBaseCommunicationMonitor.cs +++ b/src/PepperDash.Essentials.Core/Monitoring/CrestronGenericBaseCommunicationMonitor.cs @@ -11,8 +11,8 @@ using System.ComponentModel; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -68,5 +68,4 @@ namespace PepperDash.Essentials.Core else StartErrorTimers(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Monitoring/GenericCommunicationMonitor.cs b/src/PepperDash.Essentials.Core/Monitoring/GenericCommunicationMonitor.cs index 34f074d9..350ad893 100644 --- a/src/PepperDash.Essentials.Core/Monitoring/GenericCommunicationMonitor.cs +++ b/src/PepperDash.Essentials.Core/Monitoring/GenericCommunicationMonitor.cs @@ -3,321 +3,319 @@ using PepperDash.Core; using System.Threading; using PepperDash.Core.Logging; -namespace PepperDash.Essentials.Core +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 { - /// - /// 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"); - } - } - } + /// + /// Gets the Client being monitored + /// + public IBasicCommunication Client { get; private set; } /// - /// Represents a CommunicationMonitorConfig + /// Will monitor Client.BytesReceived if set to true. Otherwise the default is to monitor Client.TextReceived /// - public class CommunicationMonitorConfig - { - /// - /// Gets or sets the PollInterval - /// - public int PollInterval { get; set; } + public bool MonitorBytesReceived { get; private set; } - /// - /// Gets or sets the TimeToWarning - /// - public int TimeToWarning { get; set; } + /// + /// Return true if the Client is ISocketStatus + /// + public bool IsSocket => Client is ISocketStatus; - /// - /// Gets or sets the TimeToError - /// - public int TimeToError { get; set; } + private readonly string PollString; + private readonly Action PollAction; + private readonly long PollTime; - /// - /// Gets or sets the PollString - /// - public string PollString { get; set; } + private Timer PollTimer; - /// - /// Default constructor. Sets pollInterval to 30s, TimeToWarning to 120s, and TimeToError to 300s - /// - public CommunicationMonitorConfig() - { - PollInterval = 30000; - TimeToWarning = 120000; - TimeToError = 300000; - PollString = ""; - } - } + 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 the poll cycle + /// + 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"); + } + } +} + +/// +/// Communication Monitor Configuration from Essentials Configuration +/// +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 = ""; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorBase.cs b/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorBase.cs index 7f44fa0f..67ba1047 100644 --- a/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorBase.cs +++ b/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorBase.cs @@ -23,15 +23,15 @@ namespace PepperDash.Essentials.Core /// public event EventHandler StatusChange; - /// - /// Gets or sets the Key - /// - public string Key { get { return Parent.Key + "-comMonitor"; } } + /// + /// 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 Name + /// + public string Name { get { return "Comm. monitor"; } } /// /// Gets or sets the Parent @@ -59,7 +59,7 @@ namespace PepperDash.Essentials.Core if (value != _Status) { _Status = value; - + OnStatusChange(value); } } @@ -72,12 +72,12 @@ namespace PepperDash.Essentials.Core public string Message { get { return _Message; } - set + set { if (value == _Message) return; _Message = value; OnStatusChange(Status, value); - + } } string _Message; @@ -173,13 +173,13 @@ namespace PepperDash.Essentials.Core /// /// Resets the error timers /// - protected void ResetErrorTimers() - { - if(WarningTimer != null) - WarningTimer.Reset(WarningTime, WarningTime); - if(ErrorTimer != null) - ErrorTimer.Reset(ErrorTime, ErrorTime); + protected void ResetErrorTimers() + { + if (WarningTimer != null) + WarningTimer.Reset(WarningTime, WarningTime); + if (ErrorTimer != null) + ErrorTimer.Reset(ErrorTime, ErrorTime); - } + } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorCollection.cs b/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorCollection.cs index 58aba6a1..a6aa6c3d 100644 --- a/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorCollection.cs +++ b/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorCollection.cs @@ -11,8 +11,8 @@ using System.ComponentModel; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Collection class for multiple status monitors /// @@ -166,5 +166,4 @@ namespace PepperDash.Essentials.Core if (handler != null) handler(this, new MonitorStatusChangeEventArgs(status, message)); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Monitoring/SystemMonitorController.cs b/src/PepperDash.Essentials.Core/Monitoring/SystemMonitorController.cs index 61e70117..d09ec98f 100644 --- a/src/PepperDash.Essentials.Core/Monitoring/SystemMonitorController.cs +++ b/src/PepperDash.Essentials.Core/Monitoring/SystemMonitorController.cs @@ -1,6 +1,4 @@ - - -using System; +using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; @@ -12,1064 +10,1048 @@ using Newtonsoft.Json.Converters; using PepperDash.Essentials.Core.Bridges; using Serilog.Events; -namespace PepperDash.Essentials.Core.Monitoring +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; + /// - /// Wrapper for the static SystemMonitor class to extend functionality and provide external access - /// to SystemMonitor via APIs + /// Event fired when any SystemMonitor property changes /// - public class SystemMonitorController : EssentialsBridgeableDevice + 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 { - private const long UptimePollTime = 300000; - private CTimer _uptimePollTimer; + get { return CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance; } + } - private string _uptime; - private string _lastStart; + /// + /// 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; + } + + 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()); + } + } + + public override bool CustomActivate() + { + RefreshSystemMonitorData(); + + return base.CustomActivate(); + } + + 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; } /// - /// Event fired when any SystemMonitor property changes + /// Gets or sets the DnsServerFeedback /// - public event EventHandler SystemMonitorPropertiesChanged; + public StringFeedback DnsServerFeedback { get; protected set; } /// - /// Gets or sets the ProgramStatusFeedbackCollection + /// Gets or sets the DomainFeedback /// - public Dictionary ProgramStatusFeedbackCollection; + public StringFeedback DomainFeedback { get; protected set; } /// - /// Gets or sets the EthernetStatusFeedbackCollection + /// Gets or sets the MacAddressFeedback /// - public Dictionary EthernetStatusFeedbackCollection; + public StringFeedback MacAddressFeedback { get; protected set; } /// - /// Gets or sets the TimeZoneFeedback + /// Gets or sets the DhcpStatusFeedback /// - public IntFeedback TimeZoneFeedback { get; protected set; } + public StringFeedback DhcpStatusFeedback { get; protected set; } + /// - /// Gets or sets the TimeZoneTextFeedback + /// Gets or sets the CurrentIpAddressFeedback /// - public StringFeedback TimeZoneTextFeedback { get; protected set; } + public StringFeedback CurrentIpAddressFeedback { get; protected set; } /// - /// Gets or sets the IoControllerVersionFeedback + /// Gets or sets the CurrentSubnetMaskFeedback /// - public StringFeedback IoControllerVersionFeedback { get; protected set; } + public StringFeedback CurrentSubnetMaskFeedback { get; protected set; } /// - /// Gets or sets the SnmpVersionFeedback + /// Gets or sets the CurrentDefaultGatewayFeedback /// - public StringFeedback SnmpVersionFeedback { get; protected set; } + public StringFeedback CurrentDefaultGatewayFeedback { get; protected set; } /// - /// Gets or sets the BaCnetAppVersionFeedback + /// Gets or sets the StaticIpAddressFeedback /// - public StringFeedback BaCnetAppVersionFeedback { get; protected set; } + public StringFeedback StaticIpAddressFeedback { get; protected set; } /// - /// Gets or sets the ControllerVersionFeedback + /// Gets or sets the StaticSubnetMaskFeedback /// - public StringFeedback ControllerVersionFeedback { get; protected set; } - - //new feedbacks. Issue #50 - /// - /// Gets or sets the SerialNumberFeedback - /// - public StringFeedback SerialNumberFeedback { get; protected set; } + public StringFeedback StaticSubnetMaskFeedback { get; protected set; } /// - /// Gets or sets the ModelFeedback + /// Gets or sets the StaticDefaultGatewayFeedback /// - 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; } - } + public StringFeedback StaticDefaultGatewayFeedback { get; protected set; } /// /// Constructor /// - /// device key - public SystemMonitorController(string key) - : base(key) + /// index of the ethernet addapter + public EthernetStatusFeedbacks(short adapterIndex) { - 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( + 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_CURRENT_DHCP_STATE, adapterIndex)); - } + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, adapterIndex)); - /// - /// UpdateEthernetStatus method - /// - public void UpdateEthernetStatus() + 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_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)); + } + + 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(); + } + } +} + +public class ProgramStatusFeedbacks +{ + public event EventHandler ProgramInfoChanged; + + public Program Program; + + public ProgramInfo ProgramInfo { get; set; } + + public BoolFeedback ProgramStartedFeedback; + public BoolFeedback ProgramStoppedFeedback; + public BoolFeedback ProgramRegisteredFeedback; + public BoolFeedback ProgramUnregisteredFeedback; + + public StringFeedback ProgramNameFeedback; + public StringFeedback ProgramCompileTimeFeedback; + public StringFeedback CrestronDataBaseVersionFeedback; + // SIMPL windows version + public StringFeedback EnvironmentVersionFeedback; + public StringFeedback AggregatedProgramInfoFeedback; + + 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(); + } + + /// + /// Retrieves information about a running program + /// + 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) { - HostNameFeedback.FireUpdate(); - CurrentIpAddressFeedback.FireUpdate(); - CurrentSubnetMaskFeedback.FireUpdate(); - CurrentDefaultGatewayFeedback.FireUpdate(); - StaticIpAddressFeedback.FireUpdate(); - StaticSubnetMaskFeedback.FireUpdate(); - StaticDefaultGatewayFeedback.FireUpdate(); - DomainFeedback.FireUpdate(); - DnsServerFeedback.FireUpdate(); - MacAddressFeedback.FireUpdate(); - DhcpStatusFeedback.FireUpdate(); - } + 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; } - /// - /// Represents a ProgramStatusFeedbacks - /// - public class ProgramStatusFeedbacks + // 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")) { - /// - /// Event fired when ProgramInfo changes - /// - public event EventHandler ProgramInfoChanged; + // 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"); - /// - /// Gets or sets the Program - /// - public Program Program; + ProgramInfo.ProgramFile += string.Format(" {0}.{1}.{2}", + ProgramInfo.CompilerRevisionInfo.Major, + ProgramInfo.CompilerRevisionInfo.Minor, + ProgramInfo.CompilerRevisionInfo.Build); - /// - /// Gets or sets the ProgramInfo - /// - public ProgramInfo ProgramInfo { get; set; } + 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); - /// - /// Gets or sets the ProgramStartedFeedback - /// - public BoolFeedback ProgramStartedFeedback; + UpdateFeedbacks(); + } - /// - /// Gets or sets the ProgramStoppedFeedback - /// - public BoolFeedback ProgramStoppedFeedback; + private void UpdateFeedbacks() + { + ProgramNameFeedback.FireUpdate(); + ProgramCompileTimeFeedback.FireUpdate(); + CrestronDataBaseVersionFeedback.FireUpdate(); + EnvironmentVersionFeedback.FireUpdate(); - /// - /// Gets or sets the ProgramRegisteredFeedback - /// - public BoolFeedback ProgramRegisteredFeedback; + AggregatedProgramInfoFeedback.FireUpdate(); - /// - /// Gets or sets the ProgramUnregisteredFeedback - /// - public BoolFeedback ProgramUnregisteredFeedback; + OnProgramInfoChanged(); + } - /// - /// Gets or sets the ProgramNameFeedback - /// - public StringFeedback ProgramNameFeedback; + 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)); + } + } - /// - /// Gets or sets the ProgramCompileTimeFeedback - /// - public StringFeedback ProgramCompileTimeFeedback; + private string ParseConsoleData(string data, string line, string startString, string endString) + { + var outputData = ""; - /// - /// Gets or sets the CrestronDataBaseVersionFeedback - /// - public StringFeedback CrestronDataBaseVersionFeedback; + if (data.Length <= 0) return outputData; - // SIMPL windows version - /// - /// Gets or sets the EnvironmentVersionFeedback - /// - public StringFeedback EnvironmentVersionFeedback; + if (!data.Contains(line)) + { + return outputData; + } - /// - /// Gets or sets the AggregatedProgramInfoFeedback - /// - public StringFeedback AggregatedProgramInfoFeedback; + 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); + } - /// - /// 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; - } + return outputData; + } +} - // 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"); +/// +/// Represents a ProgramInfo +/// +public class ProgramInfo +{ + // Shared properties + /// + /// Gets the ProgramNumber + /// + [JsonProperty("programNumber")] + public uint ProgramNumber { get; private set; } - 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"); + /// + /// Gets or sets the OperatingState + /// + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("operatingState")] + public eProgramOperatingState OperatingState { get; set; } - ProgramInfo.ProgramFile += string.Format(" {0}.{1}.{2}", - ProgramInfo.CompilerRevisionInfo.Major, - ProgramInfo.CompilerRevisionInfo.Minor, - ProgramInfo.CompilerRevisionInfo.Build); + /// + /// Gets or sets the RegistrationState + /// + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("registrationState")] + public eProgramRegistrationState RegistrationState { get; set; } - 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); + /// + /// Gets or sets the ProgramFile + /// + [JsonProperty("programFile")] + public string ProgramFile { get; set; } - UpdateFeedbacks(); - } + /// + /// Gets or sets the FriendlyName + /// + [JsonProperty("friendlyName")] + public string FriendlyName { get; set; } - private void UpdateFeedbacks() - { - ProgramNameFeedback.FireUpdate(); - ProgramCompileTimeFeedback.FireUpdate(); - CrestronDataBaseVersionFeedback.FireUpdate(); - EnvironmentVersionFeedback.FireUpdate(); + /// + /// Gets or sets the CompilerRevision + /// + [JsonProperty("compilerRevision")] + public string CompilerRevision { get; set; } - 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; - } + /// + /// Gets the CompilerRevisionInfo + /// + [JsonIgnore] + public Version CompilerRevisionInfo + { + get + { + return new Version(CompilerRevision); } } /// - /// Represents a ProgramInfo + /// Gets or sets the CompileTime /// - 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 = ""; - } - } + [JsonProperty("compileTime")] + public string CompileTime { get; set; } /// - /// Represents a ProgramInfoEventArgs + /// Gets or sets the Include4Dat /// - public class ProgramInfoEventArgs : EventArgs - { - /// - /// Gets or sets the ProgramInfo - /// - public ProgramInfo ProgramInfo; + [JsonProperty("include4Dat")] + public string Include4Dat { get; set; } - /// - /// Constructor - /// - /// program info - public ProgramInfoEventArgs(ProgramInfo progInfo) - { - ProgramInfo = progInfo; - } + // 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 = ""; } -} \ No newline at end of file +} + +/// +/// Represents a ProgramInfoEventArgs +/// +public class ProgramInfoEventArgs : EventArgs +{ + /// + /// Gets or sets the ProgramInfo + /// + public ProgramInfo ProgramInfo; + + /// + /// Constructor + /// + /// program info + public ProgramInfoEventArgs(ProgramInfo progInfo) + { + ProgramInfo = progInfo; + } +} diff --git a/src/PepperDash.Essentials.Core/PartitionSensor/EssentialsPartitionController.cs b/src/PepperDash.Essentials.Core/PartitionSensor/EssentialsPartitionController.cs index ee20a22a..352d7cef 100644 --- a/src/PepperDash.Essentials.Core/PartitionSensor/EssentialsPartitionController.cs +++ b/src/PepperDash.Essentials.Core/PartitionSensor/EssentialsPartitionController.cs @@ -1,228 +1,186 @@ using PepperDash.Core; using System.Collections.Generic; -namespace PepperDash.Essentials.Core +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 { - /// - /// 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; + + public bool IsInAutoMode { get; private set; } + + private bool _partitionPresent; + + public bool PartitionPresent { - 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 { - get + if (IsInAutoMode) { - if (IsInAutoMode) - { - return _partitionSensor.PartitionPresentFeedback.BoolValue; - } - - return _partitionPresent; + return _partitionSensor.PartitionPresentFeedback.BoolValue; } - set + + return _partitionPresent; + } + set + { + if (_partitionPresent == value) { - if (_partitionPresent == value) - { - return; - } + return; + } - _partitionPresent = value; + _partitionPresent = value; - if (PartitionPresentFeedback != null) - { - PartitionPresentFeedback.FireUpdate(); - } + 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) + public EssentialsPartitionController(string key, string name, IPartitionStateProvider sensor, bool defaultToManualMode, List adjacentRoomKeys) + { + Key = key; + + Name = name; + + AdjacentRoomKeys = adjacentRoomKeys; + + if (sensor != null) { - Key = key; + _partitionSensor = sensor; - Name = name; - - AdjacentRoomKeys = adjacentRoomKeys; - - if (sensor != null) + if (!defaultToManualMode) { - _partitionSensor = sensor; - - if (!defaultToManualMode) - { - SetAutoMode(); - } - else - { - SetManualMode(); - } + SetAutoMode(); } else { SetManualMode(); } - - PartitionPresentFeedback.FireUpdate(); } - - private void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) + else { - if (IsInAutoMode) - { - PartitionPresent = e.BoolValue; - } + SetManualMode(); } - #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 + PartitionPresentFeedback.FireUpdate(); } + + private void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + if (IsInAutoMode) + { + PartitionPresent = e.BoolValue; + } + } + + #region IPartitionController Members + + public List AdjacentRoomKeys { get; private set; } + + 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(); + } + + 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(); + } + + + public void SetPartitionStatePresent() + { + if (!IsInAutoMode) + { + PartitionPresent = true; + PartitionPresentFeedback.FireUpdate(); + } + } + + public void SetPartitionStateNotPresent() + { + if (!IsInAutoMode) + { + PartitionPresent = false; + PartitionPresentFeedback.FireUpdate(); + } + } + + 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 + + public BoolFeedback PartitionPresentFeedback { get; private set; } + + #endregion + + #region IKeyName Members + + public string Name { get; private set; } + + #endregion + + #region IKeyed Members + + public string Key { get; private set; } + + #endregion } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/PartitionSensor/IPartitionStateProvider.cs b/src/PepperDash.Essentials.Core/PartitionSensor/IPartitionStateProvider.cs index 5bf40345..89f2a114 100644 --- a/src/PepperDash.Essentials.Core/PartitionSensor/IPartitionStateProvider.cs +++ b/src/PepperDash.Essentials.Core/PartitionSensor/IPartitionStateProvider.cs @@ -2,66 +2,66 @@ using Newtonsoft.Json; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +/// +/// Defines the contract for IPartitionStateProvider +/// +public interface IPartitionStateProvider : IKeyName { /// - /// Defines the contract for IPartitionStateProvider + /// Feedback indicating whether the partition is present /// - 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; } - } + [JsonIgnore] + BoolFeedback PartitionPresentFeedback { get; } /// - /// Defines the contract for IPartitionController + /// Indicates whether the partition is present /// - public interface IPartitionController : IPartitionStateProvider - { - /// - /// List of adjacent room keys - /// - [JsonProperty("adjacentRoomKeys")] - List AdjacentRoomKeys { get; } + [JsonProperty("partitionPresent")] + bool PartitionPresent { get; } +} - /// - /// Indicates whether the controller is in Auto mode or Manual mode - /// - [JsonProperty("isInAutoMode")] - bool IsInAutoMode { get; } +/// +/// Defines the contract for IPartitionController +/// +public interface IPartitionController : IPartitionStateProvider +{ + /// + /// List of adjacent room keys + /// + [JsonProperty("adjacentRoomKeys")] + List AdjacentRoomKeys { get; } - /// - /// Sets the PartitionPresent state - /// - void SetPartitionStatePresent(); + /// + /// Indicates whether the controller is in Auto mode or Manual mode + /// + [JsonProperty("isInAutoMode")] + bool IsInAutoMode { get; } - /// - /// Sets the PartitionPresent state to not present - /// - void SetPartitionStateNotPresent(); + /// + /// Sets the PartitionPresent state + /// + void SetPartitionStatePresent(); - /// - /// Toggles the PartitionPresent state - /// - void ToggglePartitionState(); + /// + /// Sets the PartitionPresent state to not present + /// + void SetPartitionStateNotPresent(); - /// - /// Sets the controller to Manual mode - /// - void SetManualMode(); + /// + /// Toggles the PartitionPresent state + /// + void ToggglePartitionState(); - /// - /// Sets the controller to Auto mode - /// - void SetAutoMode(); - } -} \ No newline at end of file + /// + /// Sets the controller to Manual mode + /// + void SetManualMode(); + + /// + /// Sets the controller to Auto mode + /// + void SetAutoMode(); +} diff --git a/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs b/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs index caee2dcd..116c4aa1 100644 --- a/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs @@ -2,18 +2,28 @@ using PepperDash.Essentials.Core.Config; using System.Collections.Generic; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + +/// +/// Defines a class that is capable of loading custom plugin device types +/// +public interface IPluginDeviceFactory : IDeviceFactory +{ /// - /// Defines a class that is capable of loading custom plugin device types + /// Required to define the minimum version for Essentials in the format xx.yy.zz /// - public interface IPluginDeviceFactory : IDeviceFactory - { - /// - /// Required to define the minimum version for Essentials in the format xx.yy.zz - /// - string MinimumEssentialsFrameworkVersion { get; } - } + string MinimumEssentialsFrameworkVersion { get; } } - +/// +/// Defines a factory for creating plugin development devices, including support for specific framework versions. +/// +/// This interface extends to provide additional functionality +/// specific to plugin development, such as access to supported framework versions. +public interface IPluginDevelopmentDeviceFactory : IPluginDeviceFactory +{ + /// + /// Gets a list of framework versions that are essential for development. + /// + List DevelopmentEssentialsFrameworkVersions { get; } +} diff --git a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs index 49ebad46..deec08cb 100644 --- a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs +++ b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs @@ -734,21 +734,22 @@ public static class PluginLoader { try { - if (typeof(IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract) + if (!typeof(IPluginDeviceFactory).IsAssignableFrom(type) || type.IsAbstract) { - var plugin = - (IPluginDeviceFactory)Activator.CreateInstance(type); - LoadCustomPlugin(plugin, loadedAssembly); + continue; } + + 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) + catch (Exception ex) { - Debug.LogMessage(LogEventLevel.Error, "Load Plugin not found. {0}.{2} is not a plugin factory. Exception: {1}", - loadedAssembly.Name, e.Message, type.Name); + Debug.LogError("Load Plugin not found. {assemblyName}.{typeName} is not a plugin factory. Exception: {exception}", + loadedAssembly.Name, type.Name, ex.Message); continue; } } @@ -830,7 +831,11 @@ public static class PluginLoader /// The assembly associated with the plugin being loaded. This is used for logging and tracking purposes. private static void LoadCustomPlugin(IPluginDeviceFactory deviceFactory, LoadedAssembly loadedAssembly) { - var passed = Global.IsRunningMinimumVersionOrHigher(deviceFactory.MinimumEssentialsFrameworkVersion); + var developmentDeviceFactory = deviceFactory as IPluginDevelopmentDeviceFactory; + + var passed = developmentDeviceFactory != null ? Global.IsRunningDevelopmentVersion + (developmentDeviceFactory.DevelopmentEssentialsFrameworkVersions, developmentDeviceFactory.MinimumEssentialsFrameworkVersion) + : Global.IsRunningMinimumVersionOrHigher(deviceFactory.MinimumEssentialsFrameworkVersion); if (!passed) { diff --git a/src/PepperDash.Essentials.Core/Presets/DevicePresets.cs b/src/PepperDash.Essentials.Core/Presets/DevicePresets.cs index 253a19e1..7346981b 100644 --- a/src/PepperDash.Essentials.Core/Presets/DevicePresets.cs +++ b/src/PepperDash.Essentials.Core/Presets/DevicePresets.cs @@ -12,284 +12,40 @@ using PepperDash.Core; using PepperDash.Core.WebApi.Presets; using Serilog.Events; -namespace PepperDash.Essentials.Core.Presets +namespace PepperDash.Essentials.Core.Presets; + +/// +/// Class that represents the model behind presets display +/// +public class DevicePresetsModel : Device { + public delegate void PresetRecalledCallback(ISetTopBoxNumericKeypad device, string channel); + + public delegate void PresetsSavedCallback(List presets); + + private readonly CCriticalSection _fileOps = new CCriticalSection(); + private readonly bool _initSuccess; + + private readonly ISetTopBoxNumericKeypad _setTopBox; + /// - /// Class that represents the model behind presets display + /// The methods on the STB device to call when dialing /// - public class DevicePresetsModel : Device + private Dictionary> _dialFunctions; + + private bool _dialIsRunning; + private Action _enterFunction; + private string _filePath; + + public DevicePresetsModel(string key, ISetTopBoxNumericKeypad setTopBox, string fileName) + : this(key, fileName) { - /// - /// 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 { - try - { - _setTopBox = setTopBox; + _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) - { + // Grab the digit functions from the device + // If any fail, the whole thing fails peacefully _dialFunctions = new Dictionary>(10) { {'1', setTopBox.Digit1}, @@ -304,89 +60,245 @@ namespace PepperDash.Essentials.Core.Presets {'0', setTopBox.Digit0}, {'-', setTopBox.Dash} }; - - _enterFunction = setTopBox.KeypadEnter; - - OnPresetRecalled(setTopBox, chanNum); - - Dial(chanNum); + } + catch + { + Debug.LogMessage(LogEventLevel.Information, "DevicePresets '{0}', not attached to INumericKeypad device. Ignoring", key); + _dialFunctions = null; + return; } - private void OnPresetRecalled(ISetTopBoxNumericKeypad setTopBox, string channel) + _enterFunction = setTopBox.KeypadEnter; + } + + 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; + } + + public event PresetRecalledCallback PresetRecalled; + public event PresetsSavedCallback PresetsSaved; + + public int PulseTime { get; set; } + public int DigitSpacingMs { get; set; } + public bool PresetsAreLoaded { get; private set; } + + public List PresetsList { get; private set; } + + public int Count + { + get { return PresetsList != null ? PresetsList.Count : 0; } + } + + public bool UseLocalImageStorage { get; set; } + public string ImagesLocalHostPrefix { get; set; } + public string ImagesPathPrefix { get; set; } + public string ListPathPrefix { get; set; } + public event EventHandler PresetsLoaded; + + + public void SetFileName(string path) + { + _filePath = ListPathPrefix + path; + + Debug.LogMessage(LogEventLevel.Verbose, this, "Setting presets file path to {0}", _filePath); + LoadChannels(); + } + + public void LoadChannels() + { + try { - var handler = PresetRecalled; + _fileOps.Enter(); - 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() - { + Debug.LogMessage(LogEventLevel.Verbose, this, "Loading presets from {0}", _filePath); + PresetsAreLoaded = false; try { - _fileOps.Enter(); - var pl = new PresetsList {Channels = PresetsList, Name = Name}; - var json = JsonConvert.SerializeObject(pl, Formatting.Indented); + var pl = JsonConvert.DeserializeObject(File.ReadToEnd(_filePath, Encoding.ASCII)); + Name = pl.Name; + PresetsList = pl.Channels; - using (var file = File.Open(_filePath, FileMode.Truncate)) - { - file.Write(json, Encoding.UTF8); - } + Debug.LogMessage(LogEventLevel.Verbose, this, "Loaded {0} presets", PresetsList.Count); } - finally + catch (Exception e) { - _fileOps.Leave(); + 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); } - } - - private void OnPresetsSaved() + finally { - var handler = PresetsSaved; - - if (handler == null) return; - - handler(PresetsList); - } - - private void Pulse(Action act) - { - act(true); - CrestronEnvironment.Sleep(PulseTime); - act(false); + _fileOps.Leave(); } } + + public void Dial(int presetNum) + { + if (presetNum <= PresetsList.Count) + { + Dial(PresetsList[presetNum - 1].Channel); + } + } + + 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); + } + + public void Dial(int presetNum, ISetTopBoxNumericKeypad setTopBox) + { + if (presetNum <= PresetsList.Count) + { + Dial(PresetsList[presetNum - 1].Channel, setTopBox); + } + } + + 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); + } + + public void UpdatePreset(int index, PresetChannel preset) + { + if (index >= PresetsList.Count) + { + return; + } + + PresetsList[index] = preset; + + SavePresets(); + + OnPresetsSaved(); + } + + 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); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Presets/DevicePresetsView.cs b/src/PepperDash.Essentials.Core/Presets/DevicePresetsView.cs index 42761de7..57be7624 100644 --- a/src/PepperDash.Essentials.Core/Presets/DevicePresetsView.cs +++ b/src/PepperDash.Essentials.Core/Presets/DevicePresetsView.cs @@ -6,88 +6,87 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core.Presets +namespace PepperDash.Essentials.Core.Presets; + +/// +/// Represents a DevicePresetsView +/// +public class DevicePresetsView { /// - /// Represents a DevicePresetsView + /// Gets or sets the ShowNumbers /// - public class DevicePresetsView + 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 the SubpageReferenceList + /// + public SubpageReferenceList SRL { get; private set; } + + /// + /// Gets the DevicePresetsModel + /// + public DevicePresetsModel Model { get; private set; } + + /// + /// Constructor + /// + /// trilst + /// device presets model + /// + public DevicePresetsView(BasicTriListWithSmartObject tl, DevicePresetsModel model) { - /// - /// 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) { - 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) { - throw new ArgumentNullException("model", "DevicePresetsView Cannot be instantiated with null model"); + SRL.AddItem(new PresetsListSubpageReferenceListItem(p, index, SRL, this)); + index++; } - 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(); + SRL.Count = (ushort)Model.PresetsList.Count; } } + + /// + /// Detach method + /// + public void Detach() + { + SRL.Clear(); + } + + void Model_PresetsLoaded(object sender, EventArgs e) + { + Detach(); + Attach(); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Presets/PresetChannel.cs b/src/PepperDash.Essentials.Core/Presets/PresetChannel.cs index 8fd15105..d7a9ffa9 100644 --- a/src/PepperDash.Essentials.Core/Presets/PresetChannel.cs +++ b/src/PepperDash.Essentials.Core/Presets/PresetChannel.cs @@ -7,48 +7,47 @@ using System.Text; using Crestron.SimplSharp; using Newtonsoft.Json; -namespace PepperDash.Essentials.Core.Presets +namespace PepperDash.Essentials.Core.Presets; + +/// +/// Represents a PresetChannel +/// +public class PresetChannel { - /// - /// 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 + /// Gets or sets the Name /// - public class PresetsList - { - /// - /// Gets or sets the Name - /// - [JsonProperty(Required=Required.Always,PropertyName = "name")] - public string Name { get; set; } + [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; } - } + /// + /// 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; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Presets/PresetsListSubpageReferenceListItem.cs b/src/PepperDash.Essentials.Core/Presets/PresetsListSubpageReferenceListItem.cs index f7bfa3bd..3453c3ad 100644 --- a/src/PepperDash.Essentials.Core/Presets/PresetsListSubpageReferenceListItem.cs +++ b/src/PepperDash.Essentials.Core/Presets/PresetsListSubpageReferenceListItem.cs @@ -10,11 +10,8 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Presets -{ - /// - /// Represents a PresetsListSubpageReferenceListItem - /// +namespace PepperDash.Essentials.Core.Presets; + public class PresetsListSubpageReferenceListItem : SubpageReferenceListItem { DevicePresetsView View; @@ -64,5 +61,4 @@ namespace PepperDash.Essentials.Core.Presets var icon = View.ShowIcon ? url : ""; Owner.StringInputSig(Index, 3).StringValue = icon; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Queues/ComsMessage.cs b/src/PepperDash.Essentials.Core/Queues/ComsMessage.cs index 1eb3a281..5d17b7fe 100644 --- a/src/PepperDash.Essentials.Core/Queues/ComsMessage.cs +++ b/src/PepperDash.Essentials.Core/Queues/ComsMessage.cs @@ -1,74 +1,72 @@ using System; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Queues +namespace PepperDash.Essentials.Core.Queues; + +/// +/// IBasicCommunication Message for IQueue +/// +public class ComsMessage : IQueueMessage { + private readonly byte[] _bytes; + private readonly IBasicCommunication _coms; + private readonly string _string; + private readonly bool _isByteMessage; + /// /// Represents a ComsMessage /// - public class ComsMessage : IQueueMessage + /// IBasicCommunication to send the message + /// Message to send + public ComsMessage(IBasicCommunication coms, string message) { - private readonly byte[] _bytes; - private readonly IBasicCommunication _coms; - private readonly string _string; - private readonly bool _isByteMessage; + Validate(coms, message); + _coms = coms; + _string = message; + } - /// - /// Constructor for a string message - /// - /// IBasicCommunication to send the message - /// Message to send - public ComsMessage(IBasicCommunication 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"); + } + + /// + /// Dispatchs the string/byte[] to the IBasicCommunication specified + /// + public void Dispatch() + { + if (_isByteMessage) { - Validate(coms, message); - _coms = coms; - _string = message; + _coms.SendBytes(_bytes); } - - /// - /// Constructor for a byte message - /// - /// IBasicCommunication to send the message - /// Message to send - public ComsMessage(IBasicCommunication coms, byte[] message) + else { - 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; + _coms.SendText(_string); } } + + /// + /// Shows either the byte[] or string to be sent + /// + public override string ToString() + { + return _bytes != null ? _bytes.ToString() : _string; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Queues/GenericQueue.cs b/src/PepperDash.Essentials.Core/Queues/GenericQueue.cs index af76f10f..8cb26524 100644 --- a/src/PepperDash.Essentials.Core/Queues/GenericQueue.cs +++ b/src/PepperDash.Essentials.Core/Queues/GenericQueue.cs @@ -6,282 +6,264 @@ using PepperDash.Core; using Serilog.Events; using Thread = Crestron.SimplSharpPro.CrestronThread.Thread; -namespace PepperDash.Essentials.Core.Queues +namespace PepperDash.Essentials.Core.Queues; + +/// +/// Threadsafe processing of queued items with pacing if required +/// +public class GenericQueue : IQueue { + private readonly string _key; + protected readonly ConcurrentQueue _queue; + protected readonly Thread _worker; + protected readonly CEvent _waitHandle = new CEvent(); + + private bool _delayEnabled; + private int _delayTime; + + private const Thread.eThreadPriority _defaultPriority = Thread.eThreadPriority.MediumPriority; + /// - /// Threadsafe processing of queued items with pacing if required + /// If the instance has been disposed. /// - public class GenericQueue : IQueue + public bool Disposed { get; private set; } + + /// + /// Returns the capacity of the CrestronQueue (fixed Size property) + /// + public int QueueCapacity { - 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 { - 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; } + 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; + } + + 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(); + } + + /// + /// Disposes the thread and cleans up resources. Thread cannot be restarted once + /// disposed. + /// + 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; + } + + ~GenericQueue() + { + Dispose(true); + } + + /// + /// Key + /// + public string Key + { + get { return _key; } + } } diff --git a/src/PepperDash.Essentials.Core/Queues/IQueue.cs b/src/PepperDash.Essentials.Core/Queues/IQueue.cs index a8cbbf6a..2eb6a5d1 100644 --- a/src/PepperDash.Essentials.Core/Queues/IQueue.cs +++ b/src/PepperDash.Essentials.Core/Queues/IQueue.cs @@ -1,22 +1,23 @@ using System; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Queues +namespace PepperDash.Essentials.Core.Queues; + + +/// +/// Defines the contract for IQueue +/// +public interface IQueue : IKeyed, IDisposable where T : class { /// - /// Defines the contract for IQueue + /// Enqueues an item /// - public interface IQueue : IKeyed, IDisposable where T : class - { - /// - /// Enqueues an item - /// - /// item to be queued - void Enqueue(T item); + /// item to be queued + void Enqueue(T item); - /// - /// gets the disposed status of the queue - /// - bool Disposed { get; } - } + /// + /// gets the disposed status of the queue + /// + bool Disposed { get; } } + diff --git a/src/PepperDash.Essentials.Core/Queues/IQueueMessage.cs b/src/PepperDash.Essentials.Core/Queues/IQueueMessage.cs index 2a050a3b..a832cd46 100644 --- a/src/PepperDash.Essentials.Core/Queues/IQueueMessage.cs +++ b/src/PepperDash.Essentials.Core/Queues/IQueueMessage.cs @@ -1,15 +1,15 @@ using System; -namespace PepperDash.Essentials.Core.Queues +namespace PepperDash.Essentials.Core.Queues; + + +/// +/// Defines the contract for IQueueMessage +/// +public interface IQueueMessage { /// - /// Defines the contract for IQueueMessage + /// Dispatches the message /// - public interface IQueueMessage - { - /// - /// Dispatches the message - /// - void Dispatch(); - } -} \ No newline at end of file + void Dispatch(); +} diff --git a/src/PepperDash.Essentials.Core/Queues/ProcessStringMessage.cs b/src/PepperDash.Essentials.Core/Queues/ProcessStringMessage.cs index 5e2db7df..34fa8617 100644 --- a/src/PepperDash.Essentials.Core/Queues/ProcessStringMessage.cs +++ b/src/PepperDash.Essentials.Core/Queues/ProcessStringMessage.cs @@ -1,48 +1,48 @@ using System; -namespace PepperDash.Essentials.Core.Queues +namespace PepperDash.Essentials.Core.Queues; + +/// +/// Message class for processing strings via an IQueue +/// +public class ProcessStringMessage : IQueueMessage { + private readonly Action _action; + private readonly string _message; + /// /// Represents a ProcessStringMessage /// - public class ProcessStringMessage : IQueueMessage + /// Message to be processed + /// Action to invoke on the message + public ProcessStringMessage(string message, Action action) { - private readonly Action _action; - private readonly string _message; + _message = message; + _action = action; + } - /// - /// 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; - /// - /// Processes the string with the given action - /// - public void Dispatch() - { - if (_action == null || String.IsNullOrEmpty(_message)) - return; + _action(_message); + } - _action(_message); - } - - /// - /// To string - /// - /// The current message - /// - /// ToString method - /// - /// - public override string ToString() - { - return _message ?? String.Empty; - } + /// + /// To string + /// + /// The current message + /// + /// ToString method + /// + /// + public override string ToString() + { + return _message ?? String.Empty; } } + diff --git a/src/PepperDash.Essentials.Core/Queues/StringResponseProcessor.cs b/src/PepperDash.Essentials.Core/Queues/StringResponseProcessor.cs index 207fd597..44c83e37 100644 --- a/src/PepperDash.Essentials.Core/Queues/StringResponseProcessor.cs +++ b/src/PepperDash.Essentials.Core/Queues/StringResponseProcessor.cs @@ -2,111 +2,104 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Queues +namespace PepperDash.Essentials.Core.Queues; + +public sealed class StringResponseProcessor : IKeyed, IDisposable { - /// - /// 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) { - private readonly Action _processStringAction; - private readonly IQueue _queue; - private readonly IBasicCommunication _coms; - private readonly CommunicationGather _gather; + _processStringAction = processStringAction; + _queue = new GenericQueue(key); - private StringResponseProcessor(string key, Action processStringAction) + CrestronEnvironment.ProgramStatusEventHandler += programEvent => { - _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) + if (programEvent != eProgramStatusEventType.Stopping) return; - if (disposing) + 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) { - if (_coms != null) - _coms.TextReceived -= OnResponseReceived; - - if (_gather != null) - { - _gather.LineReceived -= OnResponseReceived; - _gather.Stop(); - } - - _queue.Dispose(); + _gather.LineReceived -= OnResponseReceived; + _gather.Stop(); } - Disposed = true; + _queue.Dispose(); } - /// - /// Gets or sets the Disposed - /// - public bool Disposed { get; private set; } + Disposed = true; + } - /// - /// Finalizer - /// - ~StringResponseProcessor() - { - Dispose(false); - } + /// + /// If the instance has been disposed or not. If it has, you can not use it anymore + /// + public bool Disposed { get; private set; } + + ~StringResponseProcessor() + { + Dispose(false); } } diff --git a/src/PepperDash.Essentials.Core/Ramps and Increments/ActionIncrementer.cs b/src/PepperDash.Essentials.Core/Ramps and Increments/ActionIncrementer.cs index 544e7d94..ded7d9f3 100644 --- a/src/PepperDash.Essentials.Core/Ramps and Increments/ActionIncrementer.cs +++ b/src/PepperDash.Essentials.Core/Ramps and Increments/ActionIncrementer.cs @@ -6,134 +6,114 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.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 { + public int ChangeAmount { get; set; } + public int MaxValue { get; set; } + public int MinValue { get; set; } + public uint RepeatDelay { get; set; } + public uint RepeatTime { get; set; } + + Action SetAction; + Func GetFunc; + CTimer Timer; + /// - /// 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 + /// + /// + /// + /// + /// + /// 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) { - /// - /// The amount to change the value by each increment - /// - public int ChangeAmount { get; set; } + SetAction = setAction; + GetFunc = getFunc; + ChangeAmount = changeAmount; + MaxValue = maxValue; + MinValue = minValue; + RepeatDelay = repeatDelay; + RepeatTime = repeatTime; + } - /// - /// The maximum value for the incrementer - /// - public int MaxValue { get; set; } + /// + /// Starts incrementing cycle + /// + public void StartUp() + { + if (Timer != null) return; + Go(ChangeAmount); + } - /// - /// The minimum value for the incrementer - /// - public int MinValue { get; set; } + /// + /// Starts decrementing cycle + /// + public void StartDown() + { + if (Timer != null) return; + Go(-ChangeAmount); + } - /// - /// The delay before repeating starts - /// - public uint RepeatDelay { get; set; } + /// + /// Stops the repeat + /// + public void Stop() + { + if (Timer != null) + Timer.Stop(); + Timer = null; + } - /// - /// The time between repeats - /// - public uint RepeatTime { get; set; } + /// + /// 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); - Action SetAction; - Func GetFunc; - CTimer Timer; + 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); + } - /// - /// - /// - /// - /// - /// - /// - /// - /// 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) + /// + /// 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) { - SetAction = setAction; - GetFunc = getFunc; - ChangeAmount = changeAmount; - MaxValue = maxValue; - MinValue = minValue; - RepeatDelay = repeatDelay; - RepeatTime = repeatTime; + levelOut = MaxValue; + isAtLimit = true; } - - /// - /// StartUp method - /// - public void StartUp() + else if (levelIn < MinValue) { - 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; + levelOut = MinValue; + isAtLimit = true; } + else + levelOut = levelIn; + return isAtLimit; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Ramps and Increments/NumericalHelpers.cs b/src/PepperDash.Essentials.Core/Ramps and Increments/NumericalHelpers.cs index 383593f4..4feca569 100644 --- a/src/PepperDash.Essentials.Core/Ramps and Increments/NumericalHelpers.cs +++ b/src/PepperDash.Essentials.Core/Ramps and Increments/NumericalHelpers.cs @@ -4,40 +4,39 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + +/// +/// Helper methods for numerical operations +/// +public class NumericalHelpers +{ /// - /// Represents a NumericalHelpers + /// Scales a value /// - public class NumericalHelpers - { - /// - /// Scales a value - /// - /// - /// - /// - /// - /// - /// - public static double Scale(double input, double inMin, double inMax, double outMin, double outMax) + /// + /// + /// + /// + /// + /// + 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) { - //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; + 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; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Ramps and Increments/UshortSigIncrementer.cs b/src/PepperDash.Essentials.Core/Ramps and Increments/UshortSigIncrementer.cs index 02c40f69..7ee4c956 100644 --- a/src/PepperDash.Essentials.Core/Ramps and Increments/UshortSigIncrementer.cs +++ b/src/PepperDash.Essentials.Core/Ramps and Increments/UshortSigIncrementer.cs @@ -8,133 +8,93 @@ using Crestron.SimplSharpPro; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Attaches to UShortInputSig and does incremental ramping of the signal +/// +public class UshortSigIncrementer { - /// - /// Attaches to UShortInputSig and does incremental ramping of the signal - /// - public class UshortSigIncrementer + UShortInputSig TheSig; + public ushort ChangeAmount { get; set; } + public int MaxValue { get; set; } + public int MinValue { get; set; } + public uint RepeatDelay { get; set; } + public uint RepeatTime { get; set; } + bool SignedMode; + CTimer Timer; + + public UshortSigIncrementer(UShortInputSig sig, ushort changeAmount, int minValue, int maxValue, uint repeatDelay, uint repeatTime) { - UShortInputSig TheSig; + 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"); + } - /// - /// The amount to change the value by each increment - /// - public ushort ChangeAmount { get; set; } + public void StartUp() + { + if (Timer != null) return; + Go(ChangeAmount); + } - /// - /// The maximum value for the incrementer - /// - public int MaxValue { get; set; } + public void StartDown() + { + if (Timer != null) return; + Go(-ChangeAmount); + } - /// - /// The minimum value for the incrementer - /// - public int MinValue { get; set; } + void Go(int change) + { + int level; + if (SignedMode) level = TheSig.ShortValue; + else level = TheSig.UShortValue; - /// - /// The delay before repeating starts - /// - public uint RepeatDelay { get; set; } + // Fire once then pause + int newLevel = level + change; + bool atLimit = CheckLevel(newLevel, out newLevel); + SetValue((ushort)newLevel); - /// - /// The time between repeats - /// - public uint RepeatTime { get; set; } - bool SignedMode; - CTimer Timer; + 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); + } - /// - /// 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) + bool CheckLevel(int levelIn, out int levelOut) + { + bool IsAtLimit = false; + if (levelIn > MaxValue) { - 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"); + levelOut = MaxValue; + IsAtLimit = true; } - - /// - /// StartUp method - /// - public void StartUp() + else if (levelIn < MinValue) { - if (Timer != null) return; - Go(ChangeAmount); + levelOut = MinValue; + IsAtLimit = true; } + else + levelOut = levelIn; + return IsAtLimit; + } - /// - /// StartDown method - /// - public void StartDown() - { - if (Timer != null) return; - Go(-ChangeAmount); - } + public void Stop() + { + if (Timer != null) + Timer.Stop(); + Timer = null; + } - 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; - } + void SetValue(ushort value) + { + //CrestronConsole.PrintLine("Increment level:{0} / {1}", value, (short)value); + TheSig.UShortValue = value; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs b/src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs index 601c3559..81b5bf3b 100644 --- a/src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs +++ b/src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs @@ -16,613 +16,541 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; using Serilog.Events; -namespace PepperDash.Essentials.Core +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 { - /// - /// A device that when linked to a room can power the room on when enabled during scheduled hours. - /// - public class RoomOnToDefaultSourceWhenOccupied : ReconfigurableDevice + RoomOnToDefaultSourceWhenOccupiedConfig PropertiesConfig; + + public bool FeatureEnabled { get; private set; } + + public DateTime FeatureEnabledTime { get; private set; } + + ScheduledEvent FeatureEnableEvent; + + const string FeatureEnableEventName = "EnableRoomOnToDefaultSourceWhenOccupied"; + + public DateTime FeatureDisabledTime { get; private set; } + + ScheduledEvent FeatureDisableEvent; + + const string FeatureDisableEventName = "DisableRoomOnToDefaultSourceWhenOccupied"; + + ScheduledEventGroup FeatureEventGroup; + + public IRoomOccupancy Room { get; private set; } + + private Fusion.IEssentialsRoomFusionController FusionRoom; + + public RoomOnToDefaultSourceWhenOccupied(DeviceConfig config) : + base (config) { - RoomOnToDefaultSourceWhenOccupiedConfig PropertiesConfig; + PropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); - /// - /// Gets or sets the FeatureEnabled - /// - public bool FeatureEnabled { get; private set; } + FeatureEventGroup = new ScheduledEventGroup(this.Key); - /// - /// Gets or sets the FeatureEnabledTime - /// - public DateTime FeatureEnabledTime { get; private set; } + FeatureEventGroup.RetrieveAllEvents(); - ScheduledEvent FeatureEnableEvent; + // Add to the global class for tracking + Scheduler.AddEventGroup(FeatureEventGroup); - 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) + AddPostActivationAction(() => { - 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; - + // 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); + }); + } + + 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 { - try - { - FeatureEnabledTime = DateTime.Parse(PropertiesConfig.OccupancyStartTime); + 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) + if (FeatureEnabledTime != null) { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse OccupancyStartTime property: {0} \n Error: {1}", PropertiesConfig.OccupancyStartTime, e); + Debug.LogMessage(LogEventLevel.Debug, this, "Enabled Time: {0}", FeatureEnabledTime.ToString()); } - - 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(); + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyStartTime); } - 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) + catch (Exception e) { - 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; - } - } + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse OccupancyStartTime property: {0} \n Error: {1}", PropertiesConfig.OccupancyStartTime, e); } - 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) + try { - // Occupancy detected + FeatureDisabledTime = DateTime.Parse(PropertiesConfig.OccupancyEndTime); - if (FeatureEnabled) + if (FeatureDisabledTime != null) { - 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 - + Debug.LogMessage(LogEventLevel.Debug, this, "Disabled Time: {0}", FeatureDisabledTime.ToString()); } - } - } - - 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); - + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyEndTime); } - else if (schEvent.Name == FeatureDisableEventName) + catch (Exception e) { - 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(); + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse a DateTime config value \n Error: {1}", e); } - } - 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); - } + if (!PropertiesConfig.EnableRoomOnWhenOccupied) + FeatureEventGroup.ClearAllEvents(); else { - // Check if existing event has same time and recurrence as config values + AddEnableEventToGroup(); - FeatureEnableEvent = FeatureEventGroup.ScheduledEvents[FeatureEnableEventName]; - Debug.LogMessage(LogEventLevel.Debug, this, "Enable event already found in group"); + AddDisableEventToGroup(); - // 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); + FeatureEventGroup.UserGroupCallBack += new ScheduledEventGroup.UserEventGroupCallBack(FeatureEventGroup_UserGroupCallBack); - FeatureEnableEvent = null; - - CreateEvent(FeatureEnableEvent, FeatureEnableEventName); - } + FeatureEventGroup.EnableAllEvents(); } + FeatureEnabled = CheckIfFeatureShouldBeEnabled(); } + else + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to get room from Device Manager with key: {0}", PropertiesConfig.RoomKey); + } - /// - /// Adds the Enable event to the local event group and sets its properties based on config - /// - void AddDisableEventToGroup() + + 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) { - 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); - } - } + 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); - /// - /// Calculates the correct bitfield enum value for the event recurrence based on the config values - /// - /// - ScheduledEventCommon.eWeekDays CalculateDaysOfWeekRecurrence() + if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) { - ScheduledEventCommon.eWeekDays value = new ScheduledEventCommon.eWeekDays(); + SchEvent.Acknowledge(); - 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 (SchEvent.Name == FeatureEnableEventName) { - if(PropertiesConfig.EnableRoomOnWhenOccupied) + + if (PropertiesConfig.EnableRoomOnWhenOccupied) FeatureEnabled = true; - Debug.LogMessage(LogEventLevel.Debug, this, "RoomOnToDefaultSourceWhenOccupied Feature Enabled."); + Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Enabled by event.*****"); } - } - - /// - /// Callback for event that enables feature. Disables feature - /// - /// - /// - void FeatureDisableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) - { - if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) + else if (SchEvent.Name == FeatureDisableEventName) { FeatureEnabled = false; - Debug.LogMessage(LogEventLevel.Debug, this, "RoomOnToDefaultSourceWhenOccupied Feature Disabled."); + Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Disabled by event.*****"); } } } /// - /// Represents a RoomOnToDefaultSourceWhenOccupiedConfig + /// Checks if the feature should be currently enabled. Used on startup if processor starts after start time but before end time /// - public class RoomOnToDefaultSourceWhenOccupiedConfig + /// + bool CheckIfFeatureShouldBeEnabled() { - /// - /// Gets or sets the RoomKey - /// - [JsonProperty("roomKey")] - public string RoomKey { get; set; } + bool enabled = false; - /// - /// Gets or sets the EnableRoomOnWhenOccupied - /// - [JsonProperty("enableRoomOnWhenOccupied")] - public bool EnableRoomOnWhenOccupied { get; set; } + if(PropertiesConfig.EnableRoomOnWhenOccupied) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Current Time: {0} \n FeatureEnabledTime: {1} \n FeatureDisabledTime: {2}", DateTime.Now, FeatureEnabledTime, FeatureDisabledTime); - /// - /// Gets or sets the OccupancyStartTime - /// - [JsonProperty("occupancyStartTime")] - public string OccupancyStartTime { get; set; } + if (DateTime.Now.TimeOfDay.CompareTo(FeatureEnabledTime.TimeOfDay) >= 0 && FeatureDisabledTime.TimeOfDay.CompareTo(DateTime.Now.TimeOfDay) > 0) + { + if (SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(DateTime.Now, CalculateDaysOfWeekRecurrence())) + { + enabled = true; + } + } + } - /// - /// Gets or sets the OccupancyEndTime - /// - [JsonProperty("occupancyEndTime")] - public string OccupancyEndTime { get; set; } + if(enabled) + Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Enabled*****"); + else + Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Disabled*****"); - /// - /// 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; } + return enabled; } /// - /// Represents a RoomOnToDefaultSourceWhenOccupiedFactory + /// Respond to Occupancy status event /// - public class RoomOnToDefaultSourceWhenOccupiedFactory : EssentialsDeviceFactory + /// + /// + void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e) { - /// - /// Constructor for RoomOnToDefaultSourceWhenOccupiedFactory - /// - public RoomOnToDefaultSourceWhenOccupiedFactory() + Debug.LogMessage(LogEventLevel.Debug, this, "RoomIsOccupiedFeeback.OutputChange event fired. e.BoolValue: {0}", e.BoolValue); + if(e.BoolValue) { - TypeNames = new List() { "roomonwhenoccupancydetectedfeature" }; - } + // Occupancy detected - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new RoomOnToDefaultSourceWhenOccupied Device"); - return new RoomOnToDefaultSourceWhenOccupied(dc); + 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 + /// + /// + /// + 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."); + } + } +} + +public class RoomOnToDefaultSourceWhenOccupiedConfig +{ + [JsonProperty("roomKey")] + public string RoomKey { get; set; } + + [JsonProperty("enableRoomOnWhenOccupied")] + public bool EnableRoomOnWhenOccupied { get; set; } + + [JsonProperty("occupancyStartTime")] + public string OccupancyStartTime { get; set; } + + [JsonProperty("occupancyEndTime")] + public string OccupancyEndTime { get; set; } + + [JsonProperty("enableSunday")] + public bool EnableSunday { get; set; } + + [JsonProperty("enableMonday")] + public bool EnableMonday { get; set; } + + [JsonProperty("enableTuesday")] + public bool EnableTuesday { get; set; } + + [JsonProperty("enableWednesday")] + public bool EnableWednesday { get; set; } + + [JsonProperty("enableThursday")] + public bool EnableThursday { get; set; } + + [JsonProperty("enableFriday")] + public bool EnableFriday { get; set; } + + [JsonProperty("enableSaturday")] + public bool EnableSaturday { get; set; } +} + +public class RoomOnToDefaultSourceWhenOccupiedFactory : EssentialsDeviceFactory +{ + public RoomOnToDefaultSourceWhenOccupiedFactory() + { + TypeNames = new List() { "roomonwhenoccupancydetectedfeature" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new RoomOnToDefaultSourceWhenOccupied Device"); + return new RoomOnToDefaultSourceWhenOccupied(dc); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombiner.cs b/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombiner.cs index a45adb27..3a9a7409 100644 --- a/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombiner.cs +++ b/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombiner.cs @@ -8,491 +8,481 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +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; + /// - /// Represents a device that manages room combinations by controlling partitions and scenarios. + /// Gets a list of rooms represented as key-name pairs. /// - /// 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 + public List Rooms { - private EssentialsRoomCombinerPropertiesConfig _propertiesConfig; - - private IRoomCombinationScenario _currentScenario; - - private List _rooms; - - /// - /// Gets a list of rooms represented as key-name pairs. - /// - public List Rooms + get { - get - { - return _rooms.Cast().ToList(); - } + return _rooms.Cast().ToList(); } + } - private bool _isInAutoMode; + 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 + /// + /// 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 { - get - { - return _isInAutoMode; - } - set - { - if (value == _isInAutoMode) - { - return; - } - - _isInAutoMode = value; - IsInAutoModeFeedback.FireUpdate(); - } + return _isInAutoMode; } - - /// - /// Gets a value indicating whether automatic mode is disabled. - /// - public bool DisableAutoMode + set { - get + if (value == _isInAutoMode) { - 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(); - } + _isInAutoMode = value; + IsInAutoModeFeedback.FireUpdate(); + } + } - DetermineRoomCombinationScenario(); + /// + /// 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; } - /// - /// 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() + IsInAutoModeFeedback = new BoolFeedback(() => _isInAutoMode); + + // default to auto mode + IsInAutoMode = true; + + if (_propertiesConfig.defaultToManualMode) { 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() + 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) { - SetManualMode(); + DetermineRoomCombinationScenario(); } else { - SetAutoMode(); + 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); } } - /// - /// Gets or sets the RoomCombinationScenarios - /// - public List RoomCombinationScenarios { get; private set; } + var rooms = DeviceManager.AllDevices.OfType().Cast(); - /// - /// 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) + foreach (var room in rooms) { - var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey)); + room.Deactivate(); + } + } - if (partition != null) - { - partition.ToggglePartitionState(); - } + 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; } - /// - /// 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) + this.LogInformation("Determining Combination Scenario"); + + var currentScenario = RoomCombinationScenarios.FirstOrDefault((s) => { - if (IsInAutoMode) + 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) { - 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) + // Deactivate the old scenario first + if (_currentScenario != 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)); + Debug.LogMessage(LogEventLevel.Information, "Deactivating scenario {currentScenario}", this, _currentScenario.Name); + await _currentScenario.Deactivate(); + } - if (partition != null) + _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 the feedback indicating whether the system is currently in auto mode. + /// + 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. + 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. + public void ToggleMode() + { + if (IsInAutoMode) + { + SetManualMode(); + } + else + { + SetAutoMode(); + } + } + + /// + /// Gets the collection of room combination scenarios. + /// + 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) { - 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(); - } + Debug.LogMessage(LogEventLevel.Information, this, "Manually setting state to Present for: '{0}'", partition.Key); + partition.SetPartitionStatePresent(); } else { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to find partition with key: '{0}'", partitionState.PartitionKey); + 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 scenario with key: '{0}'", scenarioKey); + 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 + #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. +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" }; } /// - /// Provides a factory for creating instances of devices. + /// Creates and initializes a new instance of the device. /// - /// 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 + /// 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) { - /// - /// 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" }; - } + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new EssentialsRoomCombiner Device"); - /// - /// 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(); - var props = dc.Properties.ToObject(); - - return new EssentialsRoomCombiner(dc.Key, props); - } + return new EssentialsRoomCombiner(dc.Key, props); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index 868f3992..a8e9ae97 100644 --- a/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -1,3 +1,4 @@ + using System.Collections.Generic; using PepperDash.Core; @@ -11,10 +12,10 @@ namespace PepperDash.Essentials.Core /// 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. + /// + /// 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; } @@ -49,8 +50,8 @@ namespace PepperDash.Essentials.Core [JsonProperty("defaultScenarioKey")] public string defaultScenarioKey { get; set; } - /// - /// Gets or sets the debounce time, in seconds, for scenario changes. + /// + /// Gets or sets the debounce time, in seconds, for scenario changes. /// [JsonProperty("scenarioChangeDebounceTimeSeconds")] public int ScenarioChangeDebounceTimeSeconds { get; set; } @@ -61,14 +62,14 @@ namespace PepperDash.Essentials.Core /// public class PartitionConfig : IKeyName { - /// - /// Gets or sets the unique key associated with the object. + /// + /// 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. + /// + /// Gets or sets the name associated with the object. /// [JsonProperty("name")] public string Name { get; set; } @@ -91,26 +92,26 @@ namespace PepperDash.Essentials.Core /// public class RoomCombinationScenarioConfig : IKeyName { - /// - /// Gets or sets the key associated with the object. + /// + /// 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. + /// + /// 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. + /// + /// 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. + public bool HideInUi { get; set; } + + /// + /// Gets or sets the collection of partition states. /// [JsonProperty("partitionStates")] public List PartitionStates { get; set; } @@ -121,14 +122,14 @@ namespace PepperDash.Essentials.Core [JsonProperty("uiMap")] public Dictionary UiMap { get; set; } - /// - /// Gets or sets the list of actions to be performed during device activation. + /// + /// 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. + /// + /// Gets or sets the list of actions to be performed when a device is deactivated. /// [JsonProperty("deactivationActions")] public List DeactivationActions { get; set; } @@ -139,16 +140,16 @@ namespace PepperDash.Essentials.Core /// public class PartitionState { - /// - /// Gets or sets the partition key used to group and organize data within a storage system. + /// + /// 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. + /// + /// Gets or sets a value indicating whether a partition is currently present. /// [JsonProperty("partitionSensedState")] public bool PartitionPresent { get; set; } } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsDualDisplayRoomPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsDualDisplayRoomPropertiesConfig.cs index 83584a5f..6bda3ac9 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsDualDisplayRoomPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsDualDisplayRoomPropertiesConfig.cs @@ -1,11 +1,10 @@  -namespace PepperDash.Essentials.Room.Config -{ - /// - /// Represents a EssentialsDualDisplayRoomPropertiesConfig - /// - public class EssentialsDualDisplayRoomPropertiesConfig : EssentialsNDisplayRoomPropertiesConfig - { +namespace PepperDash.Essentials.Room.Config; + +/// +/// Represents the configuration properties for a dual display room. +/// +public class EssentialsDualDisplayRoomPropertiesConfig : EssentialsNDisplayRoomPropertiesConfig +{ - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs index 85f8ca16..abd2bce6 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs @@ -1,34 +1,33 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +/// +/// Configuration class for huddle room properties +/// +public class EssentialsHuddleRoomPropertiesConfig : EssentialsRoomPropertiesConfig { /// - /// Represents a EssentialsHuddleRoomPropertiesConfig + /// The key of the default display device /// - public class EssentialsHuddleRoomPropertiesConfig : EssentialsRoomPropertiesConfig - { - /// - /// The key of the default display device - /// - [JsonProperty("defaultDisplayKey")] - public string DefaultDisplayKey { get; set; } + [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 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 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; } - } + /// + /// The key of the default source item from the source list + /// + [JsonProperty("defaultSourceItem")] + public string DefaultSourceItem { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs index c41ed3c2..94de1d46 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs @@ -1,19 +1,16 @@  using Newtonsoft.Json; -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +/// +/// Represents a EssentialsHuddleVtc1PropertiesConfig +/// +public class EssentialsHuddleVtc1PropertiesConfig : EssentialsConferenceRoomPropertiesConfig { - /// - /// Represents a EssentialsHuddleVtc1PropertiesConfig + /// Gets or sets the DefaultDisplayKey /// - public class EssentialsHuddleVtc1PropertiesConfig : EssentialsConferenceRoomPropertiesConfig - { - /// - /// Gets or sets the DefaultDisplayKey - /// - [JsonProperty("defaultDisplayKey")] - public string DefaultDisplayKey { get; set; } - - } -} \ No newline at end of file + [JsonProperty("defaultDisplayKey")] + public string DefaultDisplayKey { get; set; } +} diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs index f65864b8..7b7d43b3 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs @@ -4,55 +4,55 @@ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.Config +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 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(); - } - - } + public string Key { get; set; } /// - /// Represents a DisplayItem + /// Gets or sets the Name /// - public class DisplayItem : IKeyName - { - /// - /// Gets or sets the Key - /// - public string Key { get; set; } - - /// - /// Gets or sets the Name - /// - public string Name { get; set; } - } + public string Name { get; set; } +} -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs index 7de2405a..9f563489 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs @@ -7,70 +7,71 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Privacy; using Serilog.Events; -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +/// +/// Helper class for EssentialsRoomConfig +/// +public class EssentialsRoomConfigHelper { /// - /// Represents a EssentialsRoomConfigHelper + /// Gets and operating, standalone emergegncy object that can be plugged into a room. + /// Returns null if there is no emergency defined /// - public class EssentialsRoomConfigHelper + public static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, IEssentialsRoom room) { - /// - /// GetEmergency method - /// - public static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, IEssentialsRoom room) + // This emergency + var emergency = props.Emergency; + if (emergency != null) { - // 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; - } + //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; } - - /// - /// - /// - /// - /// - /// - /// - /// GetMicrophonePrivacy method - /// - public static MicrophonePrivacyController GetMicrophonePrivacy( - EssentialsRoomPropertiesConfig props, IPrivacy room) + // 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) { - 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); + 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(); + 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 (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; @@ -78,13 +79,13 @@ namespace PepperDash.Essentials.Room.Config 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) => + 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; @@ -92,477 +93,335 @@ namespace PepperDash.Essentials.Room.Config mP.EnableLeds = false; }; - mP.EnableLeds = inCallRoom.InCallFeedback.BoolValue; - } - - return mP; + mP.EnableLeds = inCallRoom.InCallFeedback.BoolValue; } + return mP; } +} + +/// +/// +/// +public class EssentialsRoomPropertiesConfig +{ + [JsonProperty("addresses")] + public EssentialsRoomAddressPropertiesConfig Addresses { get; set; } + /// - /// Represents a EssentialsRoomPropertiesConfig + /// Gets or sets the Description /// - public class EssentialsRoomPropertiesConfig + [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 { - /// - /// 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 { - get + if (Help != null && !string.IsNullOrEmpty(Help.Message)) { - if (Help != null && !string.IsNullOrEmpty(Help.Message)) - { - return Help.Message; - } - else - { - return HelpMessage; - } + return Help.Message; } - } - - /// - /// 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 + else { - 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)); - } - + return HelpMessage; } } - - /// - /// 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 + /// Gets or sets the Environment /// - 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; } - } + [JsonProperty("environment")] + public EssentialsEnvironmentPropertiesConfig Environment { get; set; } /// - /// Represents a EssentialsHelpPropertiesConfig + /// Gets or sets the LogoLight /// - public class EssentialsHelpPropertiesConfig + [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; } + + [JsonProperty("fusion")] + public EssentialsRoomFusionConfig Fusion { get; set; } + + [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; } + + public EssentialsRoomPropertiesConfig() { - /// - /// Gets or sets the Message - /// - [JsonProperty("message")] - public string Message { get; set; } + LogoLight = new EssentialsLogoPropertiesConfig(); + LogoDark = new EssentialsLogoPropertiesConfig(); + } +} - /// - /// Gets or sets the ShowCallButton - /// - [JsonProperty("showCallButton")] - public bool ShowCallButton { get; set; } +public class EssentialsRoomUiBehaviorConfig +{ + [JsonProperty("disableActivityButtonsWhileWarmingCooling")] + public bool DisableActivityButtonsWhileWarmingCooling { get; set; } +} - /// - /// Defaults to "Call Help Desk" - /// - [JsonProperty("callButtonText")] - public string CallButtonText { get; set; } +public class EssentialsAvRoomPropertiesConfig : EssentialsRoomPropertiesConfig +{ + [JsonProperty("defaultAudioKey")] + public string DefaultAudioKey { get; set; } + [JsonProperty("sourceListKey")] + public string SourceListKey { get; set; } + [JsonProperty("destinationListKey")] + public string DestinationListKey { get; set; } + [JsonProperty("audioControlPointListKey")] + public string AudioControlPointListKey { get; set; } + [JsonProperty("cameraListKey")] + public string CameraListKey { get; set; } - /// - /// Constructor - /// - public EssentialsHelpPropertiesConfig() + + [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; } + + + [JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)] + public string MatrixRoutingKey { get; set; } +} + +public class EssentialsConferenceRoomPropertiesConfig : EssentialsAvRoomPropertiesConfig +{ + [JsonProperty("videoCodecKey")] + public string VideoCodecKey { get; set; } + [JsonProperty("audioCodecKey")] + public string AudioCodecKey { get; set; } + +} + +/// +/// Represents a EssentialsEnvironmentPropertiesConfig +/// +public class EssentialsEnvironmentPropertiesConfig +{ + /// + /// Gets or sets the Enabled + /// + public bool Enabled { get; set; } + + [JsonProperty("deviceKeys")] + public List DeviceKeys { get; set; } + + public EssentialsEnvironmentPropertiesConfig() + { + DeviceKeys = new List(); + } + +} + +public class EssentialsRoomFusionConfig +{ + public uint IpIdInt + { + get { - CallButtonText = "Call Help Desk"; + 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)); + } + } } - /// - /// Represents a EssentialsOneButtonMeetingPropertiesConfig - /// - public class EssentialsOneButtonMeetingPropertiesConfig - { - /// - /// Gets or sets the Enable - /// - [JsonProperty("enable")] - public bool Enable { get; set; } - } + [JsonProperty("ipId")] + public string IpId { get; set; } + + [JsonProperty("joinMapKey")] + public string JoinMapKey { get; set; } + +} + +public class EssentialsRoomMicrophonePrivacyConfig +{ + [JsonProperty("deviceKey")] + public string DeviceKey { get; set; } + + [JsonProperty("behaviour")] + public string Behaviour { get; set; } +} + +/// +/// Properties for the help text box +/// +public class EssentialsHelpPropertiesConfig +{ + [JsonProperty("message")] + public string Message { get; set; } + + [JsonProperty("showCallButton")] + public bool ShowCallButton { get; set; } /// - /// Represents a EssentialsRoomAddressPropertiesConfig + /// Defaults to "Call Help Desk" /// - public class EssentialsRoomAddressPropertiesConfig + [JsonProperty("callButtonText")] + public string CallButtonText { get; set; } + + public EssentialsHelpPropertiesConfig() { - /// - /// Gets or sets the PhoneNumber - /// - [JsonProperty("phoneNumber")] - public string PhoneNumber { get; set; } - - /// - /// Gets or sets the SipAddress - /// - [JsonProperty("sipAddress")] - public string SipAddress { get; set; } + CallButtonText = "Call Help Desk"; } +} + +/// +/// +/// +public class EssentialsOneButtonMeetingPropertiesConfig +{ + [JsonProperty("enable")] + public bool Enable { get; set; } +} + +public class EssentialsRoomAddressPropertiesConfig +{ + [JsonProperty("phoneNumber")] + public string PhoneNumber { get; set; } + + [JsonProperty("sipAddress")] + public string SipAddress { get; set; } +} +/// +/// Properties for the room's logo on panels +/// +public class EssentialsLogoPropertiesConfig +{ + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("url")] + public string Url { get; set; } /// - /// Represents a EssentialsLogoPropertiesConfig + /// Gets either the custom URL, a local-to-processor URL, or null if it's a default logo /// - public class EssentialsLogoPropertiesConfig + public string GetLogoUrlLight() { - /// - /// 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; - } + 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; } - /// - /// Represents a EssentialsRoomOccSensorConfig - /// - public class EssentialsRoomOccSensorConfig + public string GetLogoUrlDark() { - /// - /// Gets or sets the DeviceKey - /// - [JsonProperty("deviceKey")] - public string DeviceKey { get; set; } - - /// - /// Gets or sets the TimeoutMinutes - /// - [JsonProperty("timeoutMinutes")] - public int TimeoutMinutes { get; set; } + 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 EssentialsRoomTechConfig - /// - public class EssentialsRoomTechConfig - { - /// - /// Gets or sets the Password - /// - [JsonProperty("password")] - public string Password { get; set; } - } -} \ No newline at end of file +/// +/// Represents occupancy sensor(s) setup for a room +/// +public class EssentialsRoomOccSensorConfig +{ + [JsonProperty("deviceKey")] + public string DeviceKey { get; set; } + + [JsonProperty("timeoutMinutes")] + public int TimeoutMinutes { get; set; } +} + +public class EssentialsRoomTechConfig +{ + [JsonProperty("password")] + public string Password { get; set; } +} diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs index 349f44b8..f3440043 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs @@ -1,40 +1,29 @@ -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +/// +/// +/// +public class EssentialsRoomEmergencyConfig +{ + public EssentialsRoomEmergencyTriggerConfig Trigger { get; set; } + + public string Behavior { get; set; } +} + +/// +/// +/// +public class EssentialsRoomEmergencyTriggerConfig { /// - /// Represents a EssentialsRoomEmergencyConfig + /// contact,versiport /// - public class EssentialsRoomEmergencyConfig - { - /// - /// Gets or sets the Trigger - /// - public EssentialsRoomEmergencyTriggerConfig Trigger { get; set; } - - /// - /// Gets or sets the Behavior - /// - public string Behavior { get; set; } - } - + public string Type { get; set; } /// - /// Represents a EssentialsRoomEmergencyTriggerConfig + /// Input number if contact /// - public class EssentialsRoomEmergencyTriggerConfig - { - /// - /// contact,versiport - /// - public string Type { get; set; } + public int Number { get; set; } - /// - /// Input number if contact - /// - public int Number { get; set; } + public bool TriggerOnClose { get; set; } - /// - /// TriggerOnClose indicates if the trigger is on close - /// - public bool TriggerOnClose { get; set; } - - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomScheduledEventsConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomScheduledEventsConfig.cs index d7cb0514..b15bb9f8 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomScheduledEventsConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomScheduledEventsConfig.cs @@ -6,71 +6,71 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + + +/// +/// Represents a EssentialsRoomScheduledEventsConfig +/// +public class EssentialsRoomScheduledEventsConfig { /// - /// Represents a EssentialsRoomScheduledEventsConfig + /// Gets or sets the ScheduledEvents /// - public class EssentialsRoomScheduledEventsConfig - { - /// - /// Gets or sets the ScheduledEvents - /// - [JsonProperty("scheduledEvents")] - public List ScheduledEvents; - } + [JsonProperty("scheduledEvents")] + public List ScheduledEvents; +} + +/// +/// Represents a ScheduledEventConfig +/// +public class ScheduledEventConfig +{ + /// + /// Gets or sets the Key + /// + [JsonProperty("key")] + public string Key; /// - /// Represents a ScheduledEventConfig + /// Gets or sets the Name /// - public class ScheduledEventConfig - { - /// - /// Gets or sets the Key - /// - [JsonProperty("key")] - public string Key; + [JsonProperty("name")] + public string Name; - /// - /// 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 Days - /// - [JsonProperty("days")] - public ScheduledEventCommon.eWeekDays Days; + /// + /// Gets or sets the Time + /// + [JsonProperty("time")] + public string Time; - /// - /// Gets or sets the Time - /// - [JsonProperty("time")] - public string Time; + /// + /// Gets or sets the Actions + /// + [JsonProperty("actions")] + public List Actions; - /// - /// Gets or sets the Actions - /// - [JsonProperty("actions")] - public List Actions; + /// + /// Gets or sets the Persistent + /// + [JsonProperty("persistent")] + public bool Persistent; - /// - /// Gets or sets the Persistent - /// - [JsonProperty("persistent")] - public bool Persistent; + /// + /// Gets or sets the Acknowledgeable + /// + [JsonProperty("acknowledgeable")] + public bool Acknowledgeable; - /// - /// Gets or sets the Acknowledgeable - /// - [JsonProperty("acknowledgeable")] - public bool Acknowledgeable; - - /// - /// Gets or sets the Enable - /// - [JsonProperty("enable")] - public bool Enable; - } -} \ No newline at end of file + /// + /// Gets or sets the Enable + /// + [JsonProperty("enable")] + public bool Enable; +} diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsTechRoomConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsTechRoomConfig.cs index dfc3d7a6..086bf54f 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsTechRoomConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsTechRoomConfig.cs @@ -1,89 +1,87 @@  using System.Collections.Generic; using Newtonsoft.Json; -using PepperDash.Essentials.Room.Config; -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +/// +/// Configuration class for the EssentialsTechRoom. This is used to deserialize the room configuration from JSON and provide it to the room on initialization. +/// +public class EssentialsTechRoomConfig { /// - /// Represents a EssentialsTechRoomConfig + /// The key of the dummy device used to enable routing /// - public class EssentialsTechRoomConfig + [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; } + + /// + /// List of scheduled events for the room + /// + [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; } + + /// + /// Help message to show on the UI when the user clicks the help button. Can be used to provide room specific instructions for users. + /// + [JsonProperty("helpMessage")] + public string HelpMessage { get; set; } + + /// + /// Indicates the room + /// + [JsonProperty("isTvPresetsProvider")] + public bool IsTvPresetsProvider; + + /// + /// Constructor + /// + public 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(); - } + Displays = new List(); + Tuners = new List(); + ScheduledEvents = new List(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsVolumeLevelConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsVolumeLevelConfig.cs index 51172130..c1c34b9c 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsVolumeLevelConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsVolumeLevelConfig.cs @@ -1,115 +1,35 @@ using System; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +/// +/// Configuration class for volume levels in the Essentials room. This is used to configure the volume levels for the master, program, audio call receive, and audio call transmit channels in the room. +/// +[Obsolete("This class is being deprecated in favor audio control point lists in the main config. It is recommended to use the DeviceKey property to get the device from the main system and then cast it to the correct type.")] +public class EssentialsRoomVolumesConfig { - /// - /// Represents a EssentialsRoomVolumesConfig - /// - public class EssentialsRoomVolumesConfig - { - /// - /// Gets or sets the Master - /// - public EssentialsVolumeLevelConfig Master { get; set; } + public EssentialsVolumeLevelConfig Master { get; set; } + public EssentialsVolumeLevelConfig Program { get; set; } + public EssentialsVolumeLevelConfig AudioCallRx { get; set; } + public EssentialsVolumeLevelConfig AudioCallTx { 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; } - } +/// +/// Configuration class for a volume level in the Essentials room. +/// +public class EssentialsVolumeLevelConfig +{ + public string DeviceKey { get; set; } + public string Label { get; set; } + public int Level { get; set; } /// - /// Represents a EssentialsVolumeLevelConfig + /// Helper to get the device associated with key - one timer. /// - public class EssentialsVolumeLevelConfig + [Obsolete("This method references DM CHASSIS Directly and should not be used in the Core library. It is recommended to use the DeviceKey property to get the device from the main system and then cast it to the correct type.")] + public IBasicVolumeWithFeedback GetDevice() { - /// - /// 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; - } - * */ - } + throw new NotImplementedException("This method references DM CHASSIS Directly and should not be used in the Core library. It is recommended to use the DeviceKey property to get the device from the main system and then cast it to the correct type."); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/SimplRoomPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/SimplRoomPropertiesConfig.cs index 59628aed..dad8b9f2 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/SimplRoomPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/SimplRoomPropertiesConfig.cs @@ -1,53 +1,52 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +/// +/// Represents a SimplRoomPropertiesConfig +/// +public class SimplRoomPropertiesConfig : EssentialsHuddleVtc1PropertiesConfig { - /// - /// 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; } - } + /// + /// Gets or sets the RoomPhoneNumber + /// + [JsonProperty("roomPhoneNumber")] + public string RoomPhoneNumber { get; set; } /// - /// Represents a SimplSpeedDial + /// Gets or sets the RoomURI /// - 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; } - } + [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; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs b/src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs index 6582bac3..ee81c4d0 100644 --- a/src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs +++ b/src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs @@ -2,116 +2,94 @@ using Crestron.SimplSharpPro; using PepperDash.Essentials.Room.Config; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase, IEssentialsRoomEmergency { - /// - /// Represents a EssentialsRoomEmergencyContactClosure - /// - public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase, IEssentialsRoomEmergency + public event EventHandler EmergencyStateChange; + + IEssentialsRoom Room; + string Behavior; + bool TriggerOnClose; + + public bool InEmergency { get; private set; } + + public EssentialsRoomEmergencyContactClosure(string key, EssentialsRoomEmergencyConfig config, IEssentialsRoom room) : + base(key) { - /// - /// Event fired when emergency state changes - /// - public event EventHandler EmergencyStateChange; + Room = room; + var cs = Global.ControlSystem; - 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) + if (config.Trigger.Type.Equals("contact", StringComparison.OrdinalIgnoreCase)) { - Room = room; - var cs = Global.ControlSystem; - - if (config.Trigger.Type.Equals("contact", StringComparison.OrdinalIgnoreCase)) + var portNum = (uint)config.Trigger.Number; + if (portNum <= cs.NumberOfDigitalInputPorts) { - 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); + cs.DigitalInputPorts[portNum].Register(); + cs.DigitalInputPorts[portNum].StateChange += EsentialsRoomEmergencyContactClosure_StateChange; } } - - void EsentialsRoomEmergencyContactClosure_StateChange(DigitalInput digitalInput, DigitalInputEventArgs args) + else if (config.Trigger.Type.Equals("versiport", StringComparison.OrdinalIgnoreCase)) { - ContactClosure_StateChange(args.State); - } - - void ContactClosure_StateChange(bool portState) - { - if (portState && TriggerOnClose || !portState && !TriggerOnClose) + var portNum = (uint)config.Trigger.Number; + if (portNum <= cs.NumberOfVersiPorts) { - InEmergency = true; - if (EmergencyStateChange != null) - EmergencyStateChange(this, new EventArgs()); - RunEmergencyBehavior(); - } - else - { - InEmergency = false; - if (EmergencyStateChange != null) - EmergencyStateChange(this, new EventArgs()); + 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; + } - /// - /// RunEmergencyBehavior method - /// - public void RunEmergencyBehavior() + private void EssentialsRoomEmergencyContactClosure_VersiportChange(Versiport port, VersiportEventArgs args) + { + if (args.Event == eVersiportEvent.DigitalInChange) { - if (Behavior.Equals("shutdown")) - Room.Shutdown(); + 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()); } } /// - /// Defines the contract for IEssentialsRoomEmergency + /// /// - public interface IEssentialsRoomEmergency + public void RunEmergencyBehavior() { - /// - /// Event fired when emergency state changes - /// - event EventHandler EmergencyStateChange; - - /// - /// Gets or sets the InEmergency - /// - bool InEmergency { get; } + if (Behavior.Equals("shutdown")) + Room.Shutdown(); } +} + +/// +/// Describes the functionality of a room emergency contact closure +/// +public interface IEssentialsRoomEmergency +{ + event EventHandler EmergencyStateChange; + + bool InEmergency { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs b/src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs index 13ba9d66..e2d35c2a 100644 --- a/src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs +++ b/src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs @@ -12,259 +12,188 @@ using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// +/// +public abstract class EssentialsRoomBase : ReconfigurableDevice, IEssentialsRoom { /// - /// + /// /// - public abstract class EssentialsRoomBase : ReconfigurableDevice, IEssentialsRoom + public BoolFeedback OnFeedback { get; private set; } + + /// + /// Fires when the RoomOccupancy object is set + /// + public event EventHandler RoomOccupancyIsSet; + + public BoolFeedback IsWarmingUpFeedback { get; private set; } + public BoolFeedback IsCoolingDownFeedback { get; private set; } + + public IOccupancyStatusProvider RoomOccupancy { get; protected set; } + + public bool OccupancyStatusProviderIsRemote { get; private set; } + + public List EnvironmentalControlDevices { get; protected set; } + + public bool HasEnvironmentalControlDevices { - /// - /// - /// - 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 { - get - { - return EnvironmentalControlDevices != null && EnvironmentalControlDevices.Count > 0; - } + return EnvironmentalControlDevices != null && EnvironmentalControlDevices.Count > 0; } + } - /// - /// Gets or sets the IsWarmingFeedbackFunc - /// - protected abstract Func IsWarmingFeedbackFunc { get; } + protected abstract Func IsWarmingFeedbackFunc { get; } + protected abstract Func IsCoolingFeedbackFunc { get; } - /// - /// Gets or sets the IsCoolingFeedbackFunc - /// - protected abstract Func IsCoolingFeedbackFunc { get; } + /// + /// Indicates if this room is Mobile Control Enabled + /// + public bool IsMobileControlEnabled { get; private set; } - /// - /// Gets or sets the IsMobileControlEnabled - /// - public bool IsMobileControlEnabled { get; private set; } + /// + /// The bridge for this room if Mobile Control is enabled + /// + public IMobileControlRoomMessenger MobileControlRoomBridge { get; private set; } - /// - /// Gets or sets the MobileControlRoomBridge - /// - public IMobileControlRoomMessenger MobileControlRoomBridge { get; private set; } + protected const string _defaultListKey = "default"; - /// - /// The config name of the default source list - /// - protected const string _defaultListKey = "default"; - - /// - /// The config name of the source list - /// + /// + /// The config name of the source list + /// /// private string _sourceListKey; - - /// - /// Gets or sets the SourceListKey - /// - public string SourceListKey { + public string SourceListKey { get { - if(string.IsNullOrEmpty(_sourceListKey)) - { - return _defaultListKey; - } - else - { - return _sourceListKey; - } + if(string.IsNullOrEmpty(_sourceListKey)) + { + return _defaultListKey; + } + else + { + return _sourceListKey; + } } protected set { - if (value != _sourceListKey) - { - _sourceListKey = value; - } + if (value != _sourceListKey) + { + _sourceListKey = value; + } } } - private string _destinationListKey; - - /// - /// Gets or sets the DestinationListKey - /// - public string DestinationListKey + private string _destinationListKey; + public string DestinationListKey + { + get { - get + if (string.IsNullOrEmpty(_destinationListKey)) { - if (string.IsNullOrEmpty(_destinationListKey)) - { - return _defaultListKey; - } - else - { - return _destinationListKey; - } + return _defaultListKey; } - protected set + else { - if (value != _destinationListKey) - { - _destinationListKey = value; - } + return _destinationListKey; } } - - private string _audioControlPointListKey; - - /// - /// Gets or sets the AudioControlPointListKey - /// - public string AudioControlPointListKey + protected set { - get + if (value != _destinationListKey) { - if (string.IsNullOrEmpty(_audioControlPointListKey)) - { - return _defaultListKey; - } - else - { - return _destinationListKey; - } - } - protected set - { - if (value != _audioControlPointListKey) - { - _audioControlPointListKey = value; - } + _destinationListKey = value; } } + } - private string _cameraListKey; - - /// - /// Gets or sets the CameraListKey - /// - public string CameraListKey + private string _audioControlPointListKey; + public string AudioControlPointListKey + { + get { - get + if (string.IsNullOrEmpty(_audioControlPointListKey)) { - if (string.IsNullOrEmpty(_cameraListKey)) - { - return _defaultListKey; - } - else - { - return _cameraListKey; - } + return _defaultListKey; } - protected set + else { - if (value != _cameraListKey) - { - _cameraListKey = value; - } + return _destinationListKey; } } + protected set + { + if (value != _audioControlPointListKey) + { + _audioControlPointListKey = value; + } + } + } - /// - /// Gets or sets the ShutdownPromptTimer - /// - public SecondsCountdownTimer ShutdownPromptTimer { get; private set; } + private string _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 ShutdownPromptSeconds - /// - public int ShutdownPromptSeconds { get; set; } + /// + /// Timer used for informing the UIs of a shutdown + /// + public SecondsCountdownTimer ShutdownPromptTimer { get; private set; } - /// - /// Gets or sets the ShutdownVacancySeconds - /// - public int ShutdownVacancySeconds { get; set; } + /// + /// + /// + public int ShutdownPromptSeconds { get; set; } + public int ShutdownVacancySeconds { get; set; } + public eShutdownType ShutdownType { get; private set; } - /// - /// Gets or sets the ShutdownType - /// - public eShutdownType ShutdownType { get; private set; } + public EssentialsRoomEmergencyBase Emergency { get; set; } - /// - /// Gets or sets the Emergency - /// - public EssentialsRoomEmergencyBase Emergency { get; set; } + public Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; set; } - /// - /// Gets or sets the MicrophonePrivacy - /// - public Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; set; } + public string LogoUrlLightBkgnd { get; set; } - /// - /// Gets or sets the LogoUrlLightBkgnd - /// - public string LogoUrlLightBkgnd { get; set; } + public string LogoUrlDarkBkgnd { get; set; } - /// - /// Gets or sets the LogoUrlDarkBkgnd - /// - public string LogoUrlDarkBkgnd { get; set; } + protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; } - /// - /// Gets or sets the RoomVacancyShutdownTimer - /// - protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; } + public eVacancyMode VacancyMode { 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 prompt is displayed until shutdown - /// - protected int RoomVacancyShutdownSeconds; + /// + /// Seconds after vacancy detected until prompt is displayed + /// + protected int RoomVacancyShutdownPromptSeconds; - /// - /// Seconds after vacancy detected until prompt is displayed - /// - protected int RoomVacancyShutdownPromptSeconds; - - /// - /// - /// - protected abstract Func OnFeedbackFunc { get; } + /// + /// + /// + protected abstract Func OnFeedbackFunc { get; } /// /// Gets or sets the SavedVolumeLevels @@ -276,362 +205,293 @@ namespace PepperDash.Essentials.Core /// public bool ZeroVolumeWhenSwtichingVolumeDevices { get; private set; } - /// - /// Constructor for EssentialsRoomBase - /// - /// config of the device - public EssentialsRoomBase(DeviceConfig config) - : base(config) + + public EssentialsRoomBase(DeviceConfig config) + : base(config) + { + EnvironmentalControlDevices = new List(); + + // Setup the ShutdownPromptTimer + ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer"); + ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) => { - EnvironmentalControlDevices = new List(); + if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue) + ShutdownType = eShutdownType.None; + }; - // 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 - ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered + ShutdownPromptSeconds = 60; + ShutdownVacancySeconds = 120; + + ShutdownType = eShutdownType.None; - 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 - 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; - RoomVacancyShutdownPromptSeconds = 1500; // 25 min to prompt warning - RoomVacancyShutdownSeconds = 240; // 4 min after prompt will trigger shutdown prompt - VacancyMode = eVacancyMode.None; + OnFeedback = new BoolFeedback(OnFeedbackFunc); - OnFeedback = new BoolFeedback(OnFeedbackFunc); + IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc); + IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc); - IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc); - IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc); + AddPostActivationAction(() => + { + if (RoomOccupancy != null) + OnRoomOccupancyIsSet(); + }); + } - AddPostActivationAction(() => - { - if (RoomOccupancy != null) - OnRoomOccupancyIsSet(); - }); + 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; } - - /// - /// CustomActivate method - /// - /// - public override bool CustomActivate() + else { - SetUpMobileControl(); - - return base.CustomActivate(); + sourceListKey = _defaultListKey; } + } - /// - /// Sets the SourceListKey property to the passed in value or the default if no value passed in - /// - /// - protected void SetSourceListKey(string sourceListKey) + protected void SetDestinationListKey(string destinationListKey) + { + if (!string.IsNullOrEmpty(destinationListKey)) { - if (!string.IsNullOrEmpty(sourceListKey)) - { - SourceListKey = sourceListKey; - } - else - { - sourceListKey = _defaultListKey; - } + DestinationListKey = destinationListKey; } + } - /// - /// 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 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) { - if (!string.IsNullOrEmpty(destinationListKey)) - { - DestinationListKey = destinationListKey; - } + Debug.LogMessage(LogEventLevel.Debug, this, "*********************Mobile Control Bridge Not found for this room."); + IsMobileControlEnabled = false; + return; } - - /// - /// If mobile control is enabled, sets the appropriate properties - /// - void SetUpMobileControl() + else { - 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; - } + 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) + void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e) + { + switch (VacancyMode) { - switch (VacancyMode) - { - case eVacancyMode.None: - StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); + 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; - 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; - } + } + default: + break; } + } - /// - /// - /// - /// - /// - /// StartShutdown method - /// - public void StartShutdown(eShutdownType type) - { - // Check for shutdowns running. Manual should override other shutdowns + /// + /// + /// + /// + 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(); + 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); - } + 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(); + 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); - } + Debug.LogMessage(LogEventLevel.Information, this, "Vacancy Timer Started. Mode: {0}. Seconds: {1}", VacancyMode, RoomVacancyShutdownTimer.SecondsToCount); + } - /// - /// Shutdown method - /// - public void Shutdown() - { - VacancyMode = eVacancyMode.None; - EndShutdown(); - } + /// + /// Resets the vacancy mode and shutsdwon the room + /// + 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(); + /// + /// 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(); + /// + /// 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) - { + /// + /// 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); + 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 status provider is fusion, set flag to remote + if (statusProvider is Core.Fusion.IEssentialsRoomFusionController) + OccupancyStatusProviderIsRemote = true; - if(timeoutMinutes > 0) - RoomVacancyShutdownSeconds = timeoutMinutes * 60; + if(timeoutMinutes > 0) + RoomVacancyShutdownSeconds = timeoutMinutes * 60; - Debug.LogMessage(LogEventLevel.Information, this, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds); + Debug.LogMessage(LogEventLevel.Information, this, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds); - RoomOccupancy = statusProvider; + RoomOccupancy = statusProvider; - RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; - RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; + 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; - } + OnRoomOccupancyIsSet(); } - - /// - /// To describe the various ways a room may be shutting down - /// - public enum eShutdownType + + void OnRoomOccupancyIsSet() { - /// - /// No shutdown in progress - /// - None = 0, - - /// - /// Manual shutdown initiated - /// - External, - - /// - /// Vacancy based shutdown - /// - Manual, - - /// - /// Shutdown due to room vacancy - /// - Vacancy + var handler = RoomOccupancyIsSet; + if (handler != null) + handler(this, new EventArgs()); } /// - /// Enumeration of eVacancyMode values + /// To allow base class to power room on to last source /// - public enum eVacancyMode - { - /// - /// No vacancy detected - /// - None = 0, - - /// - /// InInitialVacancy - countdown to warning - /// - InInitialVacancy, - - /// - /// InShutdownWarning - countdown to shutdown - /// - InShutdownWarning - } + public abstract void PowerOnToDefaultOrLastSource(); /// - /// Enumeration of eWarmingCoolingMode values + /// To allow base class to power room on to default source /// - public enum eWarmingCoolingMode + /// + public abstract bool RunDefaultPresentRoute(); + + void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e) { - /// - /// 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) + if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false && AllowVacancyTimerToStart()) { - Key = key; + 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 +{ + None = 0, + External, + Manual, + Vacancy +} + +public enum eVacancyMode +{ + None = 0, + InInitialVacancy, + InShutdownWarning +} + +/// +/// +/// +public enum eWarmingCoolingMode +{ + None, + Warming, + Cooling +} + +public abstract class EssentialsRoomEmergencyBase : IKeyed +{ + public string Key { get; private set; } + + public EssentialsRoomEmergencyBase(string key) + { + Key = key; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/IEssentialsRoom.cs b/src/PepperDash.Essentials.Core/Room/IEssentialsRoom.cs index 3ebe28c4..681b6675 100644 --- a/src/PepperDash.Essentials.Core/Room/IEssentialsRoom.cs +++ b/src/PepperDash.Essentials.Core/Room/IEssentialsRoom.cs @@ -10,103 +10,101 @@ using PepperDash.Essentials.Core.Devices; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Describes the basic functionality of an EssentialsRoom +/// +public interface IEssentialsRoom : IKeyName, IReconfigurableDevice, IRunDefaultPresentRoute, IEnvironmentalControls { /// - /// Describes the basic functionality of an EssentialsRoom + /// Gets the PowerFeedback /// - public interface IEssentialsRoom : IKeyName, IReconfigurableDevice, IRunDefaultPresentRoute, IEnvironmentalControls - { - /// - /// Gets the PowerFeedback - /// - BoolFeedback OnFeedback { get; } + BoolFeedback OnFeedback { get; } - /// - /// Gets the IsOccupiedFeedback - /// - BoolFeedback IsWarmingUpFeedback { get; } + /// + /// Gets the IsOccupiedFeedback + /// + BoolFeedback IsWarmingUpFeedback { get; } - /// - /// Gets the IsCoolingDownFeedback - /// - BoolFeedback IsCoolingDownFeedback { get; } + /// + /// Gets the IsCoolingDownFeedback + /// + BoolFeedback IsCoolingDownFeedback { get; } - /// - /// Gets a value indicating whether mobile control is enabled for this room - /// - bool IsMobileControlEnabled { get; } + /// + /// Gets a value indicating whether mobile control is enabled for this room + /// + bool IsMobileControlEnabled { get; } - /// - /// Gets the MobileControlRoomBridge - /// - IMobileControlRoomMessenger MobileControlRoomBridge { get; } + /// + /// Gets the MobileControlRoomBridge + /// + IMobileControlRoomMessenger MobileControlRoomBridge { get; } - /// - /// Gets the SourceListKey - /// - string SourceListKey { get; } + /// + /// Gets the SourceListKey + /// + string SourceListKey { get; } - /// - /// Gets the DestinationListKey - /// - string DestinationListKey { get; } + /// + /// Gets the DestinationListKey + /// + string DestinationListKey { get; } - /// - /// Gets the AudioControlPointListKey - /// - string AudioControlPointListKey { get; } + /// + /// Gets the AudioControlPointListKey + /// + string AudioControlPointListKey { get; } - /// - /// Gets the CameraListKey - /// - string CameraListKey { get; } + /// + /// Gets the CameraListKey + /// + string CameraListKey { get; } - /// - /// Gets the ShutdownPromptTimer - /// - SecondsCountdownTimer ShutdownPromptTimer { get; } + /// + /// Gets the ShutdownPromptTimer + /// + SecondsCountdownTimer ShutdownPromptTimer { get; } - /// - /// Gets the ShutdownVacancyTimer - /// - int ShutdownPromptSeconds { get; } + /// + /// Gets the ShutdownVacancyTimer + /// + int ShutdownPromptSeconds { get; } - /// - /// Gets the ShutdownVacancySeconds - /// - int ShutdownVacancySeconds { get; } + /// + /// Gets the ShutdownVacancySeconds + /// + int ShutdownVacancySeconds { get; } - /// - /// Gets the ShutdownType - /// - eShutdownType ShutdownType { get; } + /// + /// Gets the ShutdownType + /// + eShutdownType ShutdownType { get; } - /// - /// Gets the LogoUrlLightBkgnd - /// - string LogoUrlLightBkgnd { get; } + /// + /// Gets the LogoUrlLightBkgnd + /// + string LogoUrlLightBkgnd { get; } - /// - /// Gets the LogoUrlDarkBkgnd - /// - string LogoUrlDarkBkgnd { get; } + /// + /// Gets the LogoUrlDarkBkgnd + /// + string LogoUrlDarkBkgnd { get; } - /// - /// Starts the shutdown process - /// - /// type of shutdown event - void StartShutdown(eShutdownType type); + /// + /// Starts the shutdown process + /// + /// type of shutdown event + void StartShutdown(eShutdownType type); - /// - /// Shuts down the room - /// - void Shutdown(); + /// + /// Shuts down the room + /// + void Shutdown(); - /// - /// Powers on the room to either the default source or the last source used - /// - void PowerOnToDefaultOrLastSource(); - } - -} \ No newline at end of file + /// + /// Powers on the room to either the default source or the last source used + /// + void PowerOnToDefaultOrLastSource(); +} diff --git a/src/PepperDash.Essentials.Core/Room/IRoomEventSchedule.cs b/src/PepperDash.Essentials.Core/Room/IRoomEventSchedule.cs index a42ea505..8f841def 100644 --- a/src/PepperDash.Essentials.Core/Room/IRoomEventSchedule.cs +++ b/src/PepperDash.Essentials.Core/Room/IRoomEventSchedule.cs @@ -2,39 +2,40 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +/// +/// Defines the contract for IRoomEventSchedule +/// +public interface IRoomEventSchedule { /// - /// Defines the contract for IRoomEventSchedule + /// Adds or updates a scheduled event /// - 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; - } + /// + void AddOrUpdateScheduledEvent(ScheduledEventConfig eventConfig); /// - /// Represents a ScheduledEventEventArgs + /// Removes a scheduled event by its key /// - public class ScheduledEventEventArgs : EventArgs - { - /// - /// Gets or sets the ScheduledEvents - /// - public List ScheduledEvents; - } + /// + 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; +} + diff --git a/src/PepperDash.Essentials.Core/Room/Interfaces.cs b/src/PepperDash.Essentials.Core/Room/Interfaces.cs index 0d2f0850..c0041a9a 100644 --- a/src/PepperDash.Essentials.Core/Room/Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Room/Interfaces.cs @@ -4,307 +4,308 @@ using System.Collections.Generic; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// For rooms with in call feedback +/// +public interface IHasInCallFeedback { /// - /// For rooms with in call feedback + /// Feedback indicating whether the room is currently in a call /// - public interface IHasInCallFeedback - { - /// - /// Gets the InCallFeedback - /// - BoolFeedback InCallFeedback { get; } - } + BoolFeedback InCallFeedback { get; } +} + +/// +/// For rooms with a single display +/// +public interface IHasDefaultDisplay +{ + /// + /// The default display for the room, used for presentation routing and other default routes + /// + IRoutingSink DefaultDisplay { get; } +} + +/// +/// For rooms with multiple displays +/// +[Obsolete("This interface is being deprecated in favor of using destination lists for routing to multiple displays.")] +public interface IHasMultipleDisplays +{ + /// + /// A dictionary of displays in the room with the key being the type of display (presentation, calling, etc.) and the value being the display device + /// + Dictionary Displays { get; } +} + +/// +/// For rooms with routing +/// +public interface IRunRouteAction +{ + /// + /// Runs a route action for a given route and source list key. + /// The source list key is used to determine the source for the route from the source list in the room's routing controller. + /// This allows for dynamic routing based on what source is selected in the UI for a given route. + /// + /// + /// + void RunRouteAction(string routeKey, string sourceListKey); /// - /// For rooms with a single display + /// Runs a route action for a given route and source list key with a callback for success. + /// The source list key is used to determine the source for the route from the source list in the room's routing controller. + /// This allows for dynamic routing based on what source is selected in the UI for a given route. /// - public interface IHasDefaultDisplay - { - /// - /// Gets the DefaultDisplay - /// - IRoutingSink DefaultDisplay { get; } - } + /// + /// + /// + void RunRouteAction(string routeKey, string sourceListKey, Action successCallback); +} + +/// +/// Simplified routing direct from source to destination +/// +public interface IRunDirectRouteAction +{ + /// + /// Runs a direct route from a source to a destination with an optional signal type for routing. + /// + /// + /// + /// + void RunDirectRoute(string sourceKey, string destinationKey, eRoutingSignalType type = eRoutingSignalType.AudioVideo); +} + +/// +/// Describes a room with matrix routing +/// +public interface IHasMatrixRouting : IHasRoutingEndpoints +{ + /// + /// The key of the matrix routing device in the room + /// + string MatrixRoutingDeviceKey { get; } +} + +/// +/// Describes a room with routing endpoints +/// +public interface IHasRoutingEndpoints +{ + /// + /// The keys of the endpoints in the room used for routing + /// + List EndpointKeys { get; } +} + +/// +/// Describes a room with a shutdown prompt timer +/// +public interface IShutdownPromptTimer +{ + /// + /// The shutdown prompt timer for the room + /// + SecondsCountdownTimer ShutdownPromptTimer { get; } /// - /// For rooms with multiple displays + /// Sets the number of seconds for the shutdown prompt timer /// - [Obsolete("Will be removed in a future version")] - public interface IHasMultipleDisplays - { - /// - /// Gets the Displays dictionary - /// - Dictionary Displays { get; } - } + /// + void SetShutdownPromptSeconds(int seconds); /// - /// For rooms with routing + /// Starts the shutdown process for the room with a given shutdown type /// - public interface IRunRouteAction - { - /// - /// Runs a route action - /// - /// - /// - void RunRouteAction(string routeKey, string sourceListKey); + /// + void StartShutdown(eShutdownType type); +} - /// - /// Runs a route action with a success callback - /// - /// - /// - /// - void RunRouteAction(string routeKey, string sourceListKey, Action successCallback); - } +/// +/// Describes a room with a tech password +/// +public interface ITechPassword +{ + /// + /// Event that fires with the result of validating a tech password + /// + event EventHandler TechPasswordValidateResult; /// - /// Defines the contract for IRunDirectRouteAction + /// Event that fires when the tech password is changed /// - public interface IRunDirectRouteAction - { - /// - /// Runs a direct route - /// - /// - /// - /// - void RunDirectRoute(string sourceKey, string destinationKey, eRoutingSignalType type = eRoutingSignalType.AudioVideo); - } + event EventHandler TechPasswordChanged; /// - /// Describes a room with matrix routing + /// The length of the tech password /// - public interface IHasMatrixRouting - { - /// - /// Gets the MatrixRoutingDeviceKey - /// - string MatrixRoutingDeviceKey { get; } - - /// - /// Gets the EndpointKeys - /// - List EndpointKeys { get; } - } + int TechPasswordLength { get; } /// - /// Defines the contract for IHasRoutingEndpoints + /// Validates a given tech password against the current tech password for the room. Fires the TechPasswordValidateResult event with the result of the validation. /// - public interface IHasRoutingEndpoints - { - /// - /// Gets the EndpointKeys - /// - List EndpointKeys { get; } - } + /// + void ValidateTechPassword(string password); /// - /// Describes a room with a shutdown prompt timer + /// Sets a new tech password for the room. Fires the TechPasswordChanged event when the password is successfully changed. /// - public interface IShutdownPromptTimer - { - /// - /// Gets the ShutdownPromptTimer - /// - SecondsCountdownTimer ShutdownPromptTimer { get; } + /// + /// + void SetTechPassword(string oldPassword, string newPassword); +} - /// - /// Gets the ShutdownPromptSeconds - /// - /// number of seconds to set - void SetShutdownPromptSeconds(int seconds); - - /// - /// Starts the shutdown process - /// - /// type of shutdown event - void StartShutdown(eShutdownType type); - } +/// +/// Event args for tech password validation results +/// +public class TechPasswordEventArgs : EventArgs +{ + /// + /// Indicates whether the tech password validation was successful or not + /// + public bool IsValid { get; private set; } /// - /// Defines the contract for ITechPassword + /// Constructor /// - public interface ITechPassword + /// + public TechPasswordEventArgs(bool isValid) { - /// - /// 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); + IsValid = isValid; } +} + +/// +/// For rooms that default presentation only routing +/// +public interface IRunDefaultPresentRoute +{ + /// + /// Runs the default presentation route for the room. This is typically used for a "Present" button in the UI that routes a selected source to the default presentation display without needing to specify the source or destination for the route. + /// + /// True if the route was successfully run, false otherwise. + bool RunDefaultPresentRoute(); +} + +/// +/// For rooms that have default presentation and calling routes +/// +public interface IRunDefaultCallRoute : IRunDefaultPresentRoute +{ + /// + /// Runs the default call route for the room. This is typically used for a "Call" button in the UI that routes a selected source to the default call display without needing to specify the source or destination for the route. + /// + /// True if the route was successfully run, false otherwise. + bool RunDefaultCallRoute(); +} + +/// +/// Describes environmental controls available on a room such as lighting, shades, temperature, etc. +/// +public interface IEnvironmentalControls +{ + /// + /// A list of devices in the room that can be used for environmental control such as lighting, shades, temperature, etc. + /// + List EnvironmentalControlDevices { get; } /// - /// Represents a TechPasswordEventArgs + /// Indicates whether the room has any devices that can be used for environmental control such as lighting, shades, temperature, etc. /// - public class TechPasswordEventArgs : EventArgs - { - /// - /// Gets or sets the IsValid - /// - public bool IsValid { get; private set; } + bool HasEnvironmentalControlDevices { get; } +} - /// - /// Constructor for TechPasswordEventArgs - /// - /// - public TechPasswordEventArgs(bool isValid) - { - IsValid = isValid; - } - } +/// +/// Describes a room with occupancy status +/// +public interface IRoomOccupancy:IKeyed +{ + /// + /// The occupancy status provider for the room, which provides the current occupancy status of the room based on a sensor or other input. + /// This is used for features such as automatic shutdown when the room is vacant, adjusting environmental controls based on occupancy, and other occupancy-based automation. + /// + IOccupancyStatusProvider RoomOccupancy { get; } /// - /// Defines the contract for IRunDefaultPresentRoute + /// Indicates whether the occupancy status provider for the room is remote, meaning it is not directly connected to the control system and may require additional setup or configuration to work properly. + /// This can be used to determine whether certain features that rely on occupancy status should be enabled or disabled for the room. /// - public interface IRunDefaultPresentRoute - { - /// - /// Runs the default present route - /// - /// - bool RunDefaultPresentRoute(); - } + bool OccupancyStatusProviderIsRemote { get; } /// - /// For rooms that have default presentation and calling routes + /// Sets the occupancy status provider for the room with a given timeout period for determining when the room is vacant. T + /// his is used to configure the occupancy-based features of the room based on the specific occupancy sensor or input being used and the desired timeout period for determining vacancy. /// - public interface IRunDefaultCallRoute : IRunDefaultPresentRoute - { - /// - /// Runs the default call route - /// - /// - bool RunDefaultCallRoute(); - } + /// + /// + void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes); /// - /// Describes environmental controls available on a room such as lighting, shades, temperature, etc. + /// Event handler for when the room is vacated for the timeout period, which can be used to trigger actions such as shutting down the room, adjusting environmental controls, or other automation based on vacancy. /// - public interface IEnvironmentalControls - { - /// - /// Gets the EnvironmentalControlDevices - /// - List EnvironmentalControlDevices { get; } - - /// - /// Gets a value indicating whether the room has environmental control devices - /// - bool HasEnvironmentalControlDevices { get; } - } + /// + void RoomVacatedForTimeoutPeriod(object o); /// - /// Defines the contract for IRoomOccupancy + /// Starts the timer for determining when the room is vacant based on the specified vacancy mode, which can be used to trigger actions such as shutting down the room, adjusting environmental controls, or other automation based on vacancy. /// - 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; - } + /// + void StartRoomVacancyTimer(eVacancyMode mode); /// - /// Defines the contract for IEmergency + /// Gets the current vacancy mode for the room, which indicates the current state of the room in terms of occupancy and can be used to determine whether certain features or automation should be enabled or disabled based on vacancy. /// - public interface IEmergency - { - /// - /// Gets the Emergency - /// - EssentialsRoomEmergencyBase Emergency { get; } - } + eVacancyMode VacancyMode { get; } /// - /// Defines the contract for IMicrophonePrivacy + /// Event that fires when the occupancy status for the room is set, which can be used to trigger actions such as updating the UI, adjusting environmental controls, or other automation based on occupancy status changes. /// - public interface IMicrophonePrivacy - { - /// - /// Gets the MicrophonePrivacy - /// - Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; } - } + event EventHandler RoomOccupancyIsSet; +} +/// +/// Describes a room with emergency features +/// +public interface IEmergency +{ /// - /// Defines the contract for IHasAccessoryDevices + /// The emergency base for the room, which provides access to emergency features such as triggering an emergency alert, contacting emergency services, or other emergency-related functionality. /// - public interface IHasAccessoryDevices : IKeyName - { - /// - /// Gets the AccessoryDeviceKeys - /// - List AccessoryDeviceKeys { get; } - } + EssentialsRoomEmergencyBase Emergency { get; } +} +/// +/// Describes a room with a microphone privacy controller +/// +public interface IMicrophonePrivacy +{ /// - /// Defines the contract for IHasCiscoNavigatorTouchpanel + /// The microphone privacy controller for the room, which provides access to features such as muting or unmuting microphones for privacy purposes. /// - public interface IHasCiscoNavigatorTouchpanel - { - /// - /// Gets the CiscoNavigatorTouchpanelKey - /// - string CiscoNavigatorTouchpanelKey { get; } - } + Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; } +} + +/// +/// Describes a room with a camera privacy controller +/// +public interface IHasAccessoryDevices : IKeyName +{ + /// + /// A list of keys for accessory devices in the room such as cameras, microphones, or other devices that are not part of the main control system but can be integrated for additional functionality. + /// + List AccessoryDeviceKeys { get; } +} + +/// +/// Describes a room wih a Cisco Navigator touchpanel +/// +public interface IHasCiscoNavigatorTouchpanel +{ + /// + /// The key for the Cisco Navigator touchpanel in the room, which can be used to route calls or content to the touchpanel or for other integration purposes. + /// + string CiscoNavigatorTouchpanelKey { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Room.cs b/src/PepperDash.Essentials.Core/Room/Room.cs index d9c51c9d..7ce1571c 100644 --- a/src/PepperDash.Essentials.Core/Room/Room.cs +++ b/src/PepperDash.Essentials.Core/Room/Room.cs @@ -8,8 +8,8 @@ using Crestron.SimplSharpPro; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + //*************************************************************************************************** /// @@ -87,15 +87,14 @@ namespace PepperDash.Essentials.Core { get { - return new FeedbackCollection - { - RoomIsOnFeedback, - IsCoolingDownFeedback, - IsWarmingUpFeedback - }; + return new FeedbackCollection + { + RoomIsOnFeedback, + IsCoolingDownFeedback, + IsWarmingUpFeedback + }; } } #endregion - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/iOccupancyStatusProvider.cs b/src/PepperDash.Essentials.Core/Room/iOccupancyStatusProvider.cs index 8ea858ee..28dfcd26 100644 --- a/src/PepperDash.Essentials.Core/Room/iOccupancyStatusProvider.cs +++ b/src/PepperDash.Essentials.Core/Room/iOccupancyStatusProvider.cs @@ -6,16 +6,16 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +/// +/// Defines the contract for IOccupancyStatusProvider +/// +public interface IOccupancyStatusProvider { /// - /// Defines the contract for IOccupancyStatusProvider + /// Gets the RoomIsOccupiedFeedback /// - public interface IOccupancyStatusProvider - { - /// - /// Gets the RoomIsOccupiedFeedback - /// - BoolFeedback RoomIsOccupiedFeedback { get; } - } -} \ No newline at end of file + BoolFeedback RoomIsOccupiedFeedback { get; } +} diff --git a/src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs b/src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs index 6d127622..79854d3c 100644 --- a/src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs +++ b/src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs @@ -1,39 +1,32 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; +using PepperDash.Core; -using PepperDash.Core; +namespace PepperDash.Essentials.Core.Routing; -namespace PepperDash.Essentials.Core.Routing +/// +/// Represents a DummyRoutingInputsDevice +/// +public class DummyRoutingInputsDevice : Device, IRoutingSource, IRoutingOutputs { - /// - /// 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 { - /// - /// Gets or sets the AudioVideoOutputPort - /// - public RoutingOutputPort AudioVideoOutputPort { get; private set; } + get { return new RoutingPortCollection() { AudioVideoOutputPort }; } + } - /// - /// 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); - } + /// + /// constructor + /// + /// key for special device + public DummyRoutingInputsDevice(string key) : base(key) + { + AudioVideoOutputPort = new RoutingOutputPort("internal", eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.BackplaneOnly, + null, this, true); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/Extensions.cs b/src/PepperDash.Essentials.Core/Routing/Extensions.cs index 3797f5e2..b4335074 100644 --- a/src/PepperDash.Essentials.Core/Routing/Extensions.cs +++ b/src/PepperDash.Essentials.Core/Routing/Extensions.cs @@ -2,447 +2,436 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using Crestron.SimplSharpPro.Keypads; using PepperDash.Essentials.Core.Queues; using PepperDash.Essentials.Core.Routing; using Serilog.Events; using Debug = PepperDash.Core.Debug; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +/// +/// Extensions added to any IRoutingInputs classes to provide discovery-based routing +/// on those destinations. +/// +public static class Extensions { + /// + /// 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(); /// - /// Extensions added to any IRoutingInputs classes to provide discovery-based routing - /// on those destinations. + /// A queue to process route requests and releases sequentially. /// - public static class Extensions + private static readonly GenericQueue routeRequestQueue = new GenericQueue("routingQueue"); + + /// + /// 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 = "") { - /// - /// 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(); + // Remove this line before committing!!!!! + var frame = new StackFrame(1, true); + Debug.LogMessage(LogEventLevel.Information, "ReleaseAndMakeRoute Called from {method} with params {destinationKey}:{sourceKey}:{signalType}:{destinationPortKey}:{sourcePortKey}", frame.GetMethod().Name, destination.Key, source.Key, signalType.ToString(), destinationPortKey, sourcePortKey); - /// - /// A queue to process route requests and releases sequentially. - /// - private static readonly GenericQueue routeRequestQueue = new GenericQueue("routingQueue"); + 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); - /// - /// 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 = "") + 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 + 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 + 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.LogMessage(LogEventLevel.Information, "Removing route request for {destination}", null, destinationKey); + + var result = RouteRequests.Remove(destinationKey); + + var messageTemplate = result ? "Route Request for {destination} removed" : "Route Request for {destination} not found"; + + Debug.LogMessage(LogEventLevel.Information, messageTemplate, null, 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))) { - // Remove this line before committing!!!!! - var frame = new StackFrame(1, true); - Debug.LogMessage(LogEventLevel.Information, "ReleaseAndMakeRoute Called from {method} with params {destinationKey}:{sourceKey}:{signalType}:{destinationPortKey}:{sourcePortKey}", frame.GetMethod().Name, destination.Key, source.Key, signalType.ToString(), destinationPortKey, sourcePortKey); + var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, signalType); + Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key, signalType); - 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); + if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort)) + singleTypeRouteDescriptor = null; - 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.LogMessage(LogEventLevel.Information, "Removing route request for {destination}", null, destinationKey); - - var result = RouteRequests.Remove(destinationKey); - - var messageTemplate = result ? "Route Request for {destination} removed" : "Route Request for {destination} not found"; - - Debug.LogMessage(LogEventLevel.Information, messageTemplate, null, 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 routes = singleTypeRouteDescriptor?.Routes ?? new List(); + foreach (var route in routes) { - var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, signalType); - Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, 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.LogMessage(LogEventLevel.Verbose, "Route for device: {route}", destination, route.ToString()); - } - - return (singleTypeRouteDescriptor, null); - } - // otherwise, audioVideo needs to be handled as two steps. - - Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {destinationKey} to {sourceKey} of type {type}", destination, source.Key, signalType); - - RouteDescriptor audioRouteDescriptor; - - if (signalType.HasFlag(eRoutingSignalType.SecondaryAudio)) - { - audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.SecondaryAudio); - } - else - { - audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio); + Debug.LogMessage(LogEventLevel.Verbose, "Route for device: {route}", destination, route.ToString()); } - var audioSuccess = destination.GetRouteToSource(source, null, null, signalType.HasFlag(eRoutingSignalType.SecondaryAudio) ? eRoutingSignalType.SecondaryAudio : eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort); + return (singleTypeRouteDescriptor, null); + } + // otherwise, audioVideo needs to be handled as two steps. - if (!audioSuccess) - Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key); + Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key); - var videoRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Video); + RouteDescriptor audioRouteDescriptor; - var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, videoRouteDescriptor, destinationPort, sourcePort); - - if (!videoSuccess) - Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key); - - foreach (var route in audioRouteDescriptor.Routes) - { - Debug.LogMessage(LogEventLevel.Verbose, "Audio route for device: {route}", destination, route.ToString()); - } - - foreach (var route in videoRouteDescriptor.Routes) - { - Debug.LogMessage(LogEventLevel.Verbose, "Video route for device: {route}", destination, route.ToString()); - } - - - if (!audioSuccess && !videoSuccess) - return (null, null); - - - return (audioRouteDescriptor, videoRouteDescriptor); + if (signalType.HasFlag(eRoutingSignalType.SecondaryAudio)) + { + audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.SecondaryAudio); + } else + { + audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio); } - /// - /// 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) + var audioSuccess = destination.GetRouteToSource(source, null, null, signalType.HasFlag(eRoutingSignalType.SecondaryAudio) ? eRoutingSignalType.SecondaryAudio : eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort); + + if (!audioSuccess) + Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key); + + var videoRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Video); + + var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, videoRouteDescriptor, destinationPort, sourcePort); + + if (!videoSuccess) + Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key); + + foreach (var route in audioRouteDescriptor.Routes) { - if (destination == null) throw new ArgumentNullException(nameof(destination)); - if (source == null) throw new ArgumentNullException(nameof(source)); - if (destinationPort == null) Debug.LogMessage(LogEventLevel.Information, "Destination port is null"); - if (sourcePort == null) Debug.LogMessage(LogEventLevel.Information, "Source port is null"); + Debug.LogMessage(LogEventLevel.Verbose, "Audio route for device: {route}", destination, route.ToString()); + } - var routeRequest = new RouteRequest - { - Destination = destination, - DestinationPort = destinationPort, - Source = source, - SourcePort = sourcePort, - SignalType = signalType - }; + foreach (var route in videoRouteDescriptor.Routes) + { + Debug.LogMessage(LogEventLevel.Verbose, "Video route for device: {route}", destination, route.ToString()); + } - 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; + if (!audioSuccess && !videoSuccess) + return (null, null); - coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; - RouteRequests[destination.Key] = routeRequest; + return (audioRouteDescriptor, videoRouteDescriptor); + } - Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is cooling down and already has a routing request stored. Storing new route request to route to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key); + /// + /// 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.LogMessage(LogEventLevel.Information, "Destination port is null"); + if (sourcePort == null) Debug.LogMessage(LogEventLevel.Information, "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.LogMessage(LogEventLevel.Information, "Device: {destination} is cooling down and already has a routing request stored. Storing new route request to route to source key: {sourceKey}", null, 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.LogMessage(LogEventLevel.Information, "Device: {destination} is cooling down. Storing route request to route to source key: {sourceKey}", null, 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.LogMessage(LogEventLevel.Information, "Device: {destination} is NOT cooling down. Removing stored route request and routing to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key); + } + + routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination,destinationPort?.Key ?? string.Empty, false)); + + routeRequestQueue.Enqueue(new RouteRequestQueueItem(RunRouteRequest, routeRequest)); + } + + /// + /// 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; - } - //New Request - if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) - { - coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; + var (audioOrSingleRoute, videoRoute) = request.Destination.GetRouteToSource(request.Source, request.SignalType, request.DestinationPort, request.SourcePort); - RouteRequests.Add(destination.Key, routeRequest); - - Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is cooling down. Storing route request to route to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key); + if (audioOrSingleRoute == null && videoRoute == null) return; - } - if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false) + RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(audioOrSingleRoute); + + if (videoRoute != null) { - var handledRequest = RouteRequests[destination.Key]; - - coolingDevice.IsCoolingDownFeedback.OutputChange -= handledRequest.HandleCooldown; - - RouteRequests.Remove(destination.Key); - - Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is NOT cooling down. Removing stored route request and routing to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key); + RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(videoRoute); } - routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, destinationPort?.Key ?? string.Empty, false)); + Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination); - routeRequestQueue.Enqueue(new RouteRequestQueueItem(RunRouteRequest, routeRequest)); - } - - /// - /// 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) + audioOrSingleRoute.ExecuteRoutes(); + videoRoute?.ExecuteRoutes(); + } catch(Exception ex) { - try - { - if (request.Source == null) - return; - - var (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.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination); - - audioOrSingleRoute.ExecuteRoutes(); - videoRoute?.ExecuteRoutes(); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Exception Running Route Request {request}", null, request); - } - } - - /// - /// 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.LogMessage(LogEventLevel.Information, "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.LogMessage(LogEventLevel.Information, "Releasing current route: {0}", destination, current.Source.Key); - current.ReleaseRoutes(clearRoute); - } - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Exception releasing route for '{destination}':'{inputPortKey}'", null, destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); - } - } - - /// - /// 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 to use for the route - /// The specific source output port to use (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++; - - Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {cycle} {sourceKey}:{sourcePortKey}--> {destinationKey}:{destinationPortKey} {type}", null, cycle, source.Key, sourcePort?.Key ?? "auto", destination.Key, destinationPort?.Key ?? "auto", signalType.ToString()); - - RoutingInputPort goodInputPort = null; - - IEnumerable destinationTieLines; - TieLine directTie = null; - - if (destinationPort == null) - { - destinationTieLines = TieLineCollection.Default.Where(t => - t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type.HasFlag(signalType) || signalType == eRoutingSignalType.AudioVideo)); - } - else - { - destinationTieLines = TieLineCollection.Default.Where(t => t.DestinationPort.ParentDevice.Key == destination.Key && 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.DestinationPort.ParentDevice.Key == destination.Key && 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.ParentDevice.Key == destination.Key && 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.DestinationPort.ParentDevice.Key == destination.Key && 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.ParentDevice.Key == destination.Key && 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.LogMessage(LogEventLevel.Verbose, "is not directly connected to {sourceKey}. Walking down tie lines", destination, 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.LogMessage(LogEventLevel.Verbose, "Skipping input {midpointDeviceKey} on {destinationKey}, this was already checked", destination, midpointDevice.Key, destination.Key); - continue; - } - - var midpointOutputPort = tieLine.SourcePort; - - Debug.LogMessage(LogEventLevel.Verbose, "Trying to find route on {midpointDeviceKey}", destination, 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.LogMessage(LogEventLevel.Verbose, "Upstream device route found", destination); - Debug.LogMessage(LogEventLevel.Verbose, "Route found on {midpointDeviceKey}", destination, midpointDevice.Key); - Debug.LogMessage(LogEventLevel.Verbose, "TieLine: SourcePort: {SourcePort} DestinationPort: {DestinationPort}", destination, tieLine.SourcePort, tieLine.DestinationPort); - goodInputPort = tieLine.DestinationPort; - break; // Stop looping the inputs in this cycle - } - } - } - - - if (goodInputPort == null) - { - Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key); - 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.LogMessage(LogEventLevel.Verbose, "No routing. Passthrough device", destination); - - return true; + Debug.LogMessage(ex, "Exception Running Route Request {request}", null, request); } } + + /// + /// 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.LogMessage(LogEventLevel.Information, "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.LogMessage(LogEventLevel.Information, "Releasing current route: {0}", destination, current.Source.Key); + current.ReleaseRoutes(clearRoute); + } + } catch (Exception ex) + { + Debug.LogMessage(ex, "Exception releasing route for '{destination}':'{inputPortKey}'",null, destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); + } + } + + /// + /// 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 + /// The RoutingOutputPort whose link is being checked for a route + /// The RoutingOutputPort to use for the route + /// Prevents Devices from being twice-checked + /// This recursive function should not be called with AudioVideo + /// Just an informational counter + /// The RouteDescriptor being populated as the route is discovered + /// true if source is hit + private static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, + RoutingOutputPort outputPortToUse, List alreadyCheckedDevices, + eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable, RoutingInputPort destinationPort, RoutingOutputPort sourcePort) + { + cycle++; + + Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {cycle} {sourceKey}:{sourcePortKey}--> {destinationKey}:{destinationPortKey} {type}", null, cycle, source.Key, sourcePort?.Key ?? "auto", destination.Key, destinationPort?.Key ?? "auto", signalType.ToString()); + + RoutingInputPort goodInputPort = null; + + IEnumerable destinationTieLines; + TieLine directTie = null; + + if (destinationPort == null) + { + destinationTieLines = TieLineCollection.Default.Where(t => + t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type.HasFlag(signalType) || signalType == eRoutingSignalType.AudioVideo)); + } + else + { + destinationTieLines = TieLineCollection.Default.Where(t => t.DestinationPort.ParentDevice.Key == destination.Key && 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.DestinationPort.ParentDevice.Key == destination.Key && 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.ParentDevice.Key == destination.Key && 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.DestinationPort.ParentDevice.Key == destination.Key && 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.ParentDevice.Key == destination.Key && 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.LogMessage(LogEventLevel.Verbose, "is not directly connected to {sourceKey}. Walking down tie lines", destination, 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.LogMessage(LogEventLevel.Verbose, "Skipping input {midpointDeviceKey} on {destinationKey}, this was already checked", destination, midpointDevice.Key, destination.Key); + continue; + } + + var midpointOutputPort = tieLine.SourcePort; + + Debug.LogMessage(LogEventLevel.Verbose, "Trying to find route on {midpointDeviceKey}", destination, 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.LogMessage(LogEventLevel.Verbose, "Upstream device route found", destination); + Debug.LogMessage(LogEventLevel.Verbose, "Route found on {midpointDeviceKey}", destination, midpointDevice.Key); + Debug.LogMessage(LogEventLevel.Verbose, "TieLine: SourcePort: {SourcePort} DestinationPort: {DestinationPort}", destination, tieLine.SourcePort, tieLine.DestinationPort); + goodInputPort = tieLine.DestinationPort; + break; // Stop looping the inputs in this cycle + } + } + } + + + if (goodInputPort == null) + { + Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key); + 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.LogMessage(LogEventLevel.Verbose, "No routing. Passthrough device", destination); + + return true; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs b/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs index a9e13a07..107501b3 100644 --- a/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs +++ b/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs @@ -1,15 +1,4 @@ -/* 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; +using System; namespace PepperDash.Essentials.Core { diff --git a/src/PepperDash.Essentials.Core/Routing/IInputSync.cs b/src/PepperDash.Essentials.Core/Routing/IInputSync.cs index 50f2b5fb..4898702f 100644 --- a/src/PepperDash.Essentials.Core/Routing/IInputSync.cs +++ b/src/PepperDash.Essentials.Core/Routing/IInputSync.cs @@ -1,9 +1,5 @@ using PepperDash.Core; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace PepperDash.Essentials.Core.Routing { diff --git a/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs b/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs index f2837350..d2752f4a 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs @@ -1,13 +1,13 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +/// +/// Defines the contract for IRmcRouting +/// +public interface IRmcRouting : IRoutingNumeric { /// - /// Defines the contract for IRmcRouting + /// Feedback for the current Audio/Video source as a number /// - public interface IRmcRouting : IRoutingNumeric - { - /// - /// Feedback for the current Audio/Video source as a number - /// - IntFeedback AudioVideoSourceNumericFeedback { get; } - } -} \ No newline at end of file + IntFeedback AudioVideoSourceNumericFeedback { get; } +} diff --git a/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs index ab14d066..660183c1 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs @@ -1,9 +1,8 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines an IRmcRouting with a feedback event +/// +public interface IRmcRoutingWithFeedback : IRmcRouting { - /// - /// Defines the contract for IRmcRoutingWithFeedback - /// - public interface IRmcRoutingWithFeedback : IRmcRouting - { - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRouting.cs b/src/PepperDash.Essentials.Core/Routing/IRouting.cs index 64bcd7a5..dd8ed041 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRouting.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRouting.cs @@ -1,15 +1,15 @@ 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 +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 @@ -18,10 +18,9 @@ namespace PepperDash.Essentials.Core /// 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); - }*/ -} \ No newline at end of file +/*public interface IRouting : IRoutingInputsOutputs +{ + void ExecuteSwitch(TInputSelector inputSelector, TOutputSelector outputSelector, eRoutingSignalType signalType); +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs index 253ab8ee..a4e18e83 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs @@ -1,19 +1,15 @@ using System; - using PepperDash.Core; +namespace PepperDash.Essentials.Core; - -namespace PepperDash.Essentials.Core +/// +/// Defines the contract for IRoutingFeedback +/// +public interface IRoutingFeedback : IKeyName { /// - /// Defines the contract for IRoutingFeedback + /// Event raised when a numeric switch changes /// - public interface IRoutingFeedback : IKeyName - { - /// - /// Event raised when a numeric switch changes - /// - event EventHandler NumericSwitchChange; - //void OnSwitchChange(RoutingNumericEventArgs e); - } -} \ No newline at end of file + event EventHandler NumericSwitchChange; + //void OnSwitchChange(RoutingNumericEventArgs e); +} diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs index a2b4c54e..10516aee 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs @@ -9,8 +9,8 @@ using Crestron.SimplSharpPro.DM; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Defines the contract for IRoutingHasVideoInputSyncFeedbacks @@ -21,5 +21,4 @@ namespace PepperDash.Essentials.Core /// Video Input Sync Feedbacks /// FeedbackCollection VideoInputSyncFeedbacks { get; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingInputSlot.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingInputSlot.cs index f620f8bf..0137d6c1 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingInputSlot.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingInputSlot.cs @@ -1,13 +1,14 @@ -namespace PepperDash.Essentials.Core.Routing +namespace PepperDash.Essentials.Core.Routing; + + +/// +/// Defines the contract for IRoutingInputSlot +/// +public interface IRoutingInputSlot : IRoutingSlot, IOnline, IVideoSync { /// - /// Defines the contract for IRoutingInputSlot + /// Gets the Tx device key /// - public interface IRoutingInputSlot: IRoutingSlot, IOnline, IVideoSync - { - /// - /// Gets the Tx device key - /// - string TxDeviceKey { get; } - } + string TxDeviceKey { get; } } + diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs index 9543bb54..1b285e84 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs @@ -1,21 +1,14 @@ using PepperDash.Core; +namespace PepperDash.Essentials.Core; - -namespace PepperDash.Essentials.Core +/// +/// Defines the contract for IRoutingInputs +/// +public interface IRoutingInputs : IKeyed { /// - /// Defines the contract for IRoutingInputs + /// Collection of Input Ports /// - public interface IRoutingInputs : IKeyed - { - /// - /// Collection of Input Ports - /// - RoutingPortCollection InputPorts { get; } - } + RoutingPortCollection InputPorts { get; } +} -/* public interface IRoutingInputs : IKeyed - { - RoutingPortCollection, TSelector> InputPorts { get; } - }*/ -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs index 89e4d031..9257b3d9 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs @@ -1,16 +1,9 @@ -namespace PepperDash.Essentials.Core -{ - /// - /// Defines the contract for IRoutingInputsOutputs - /// - public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs - { - } +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 - { - }*/ -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs index cd91daa0..ba334afa 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs @@ -1,16 +1,16 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +/// +/// Defines the contract for IRoutingNumeric +/// +public interface IRoutingNumeric : IRouting { /// - /// Defines the contract for IRoutingNumeric + /// Executes a numeric switch on the device /// - 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); - } -} \ No newline at end of file + /// input selector + /// output selector + /// type of signal + void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type); +} diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs index 33a837a8..a59e9699 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs @@ -1,9 +1,8 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines an IRoutingNumeric with a feedback event +/// +public interface IRoutingNumericWithFeedback : IRoutingNumeric, IRoutingFeedback { - /// - /// Defines the contract for IRoutingNumericWithFeedback - /// - public interface IRoutingNumericWithFeedback : IRoutingNumeric, IRoutingFeedback - { - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingOutputSlot.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingOutputSlot.cs index 266e0724..ded827e7 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingOutputSlot.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingOutputSlot.cs @@ -1,26 +1,27 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core.Routing +namespace PepperDash.Essentials.Core.Routing; + + +/// +/// Defines the contract for IRoutingOutputSlot +/// +public interface IRoutingOutputSlot : IRoutingSlot { /// - /// Defines the contract for IRoutingOutputSlot + /// Event raised when output slot changes /// - public interface IRoutingOutputSlot : IRoutingSlot - { - /// - /// Event raised when output slot changes - /// - event EventHandler OutputSlotChanged; + event EventHandler OutputSlotChanged; - /// - /// Gets the Rx device key - /// - string RxDeviceKey { get; } + /// + /// Gets the Rx device key + /// + string RxDeviceKey { get; } - /// - /// Gets the current routes - /// - Dictionary CurrentRoutes { get; } - } + /// + /// Gets the current routes + /// + Dictionary CurrentRoutes { get; } } + diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs index c26e7b70..da2f6362 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs @@ -1,22 +1,16 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines the contract for IRoutingOutputs +/// +public interface IRoutingOutputs : IKeyed { - /// - /// Defines the contract for IRoutingOutputs + /// Collection of Output Ports /// - public interface IRoutingOutputs : IKeyed - { - /// - /// Collection of Output Ports - /// - RoutingPortCollection OutputPorts { get; } - } + RoutingPortCollection OutputPorts { get; } +} -/* public interface IRoutingOutputs : IKeyed - { - RoutingPortCollection, TSelector> OutputPorts { get; } - }*/ -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs index 6e599f29..b8af02d9 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs @@ -1,29 +1,29 @@ -using PepperDash.Essentials.Core.Routing; +using PepperDash.Essentials.Core.Routing; -namespace PepperDash.Essentials.Core +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 { /// - /// Defines the contract for IRoutingSink + /// Gets the current input port for this routing sink. /// - public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange - { - } + RoutingInputPort CurrentInputPort { get; } +} - /// - /// 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 +{ +} - /// - /// Interface for routing sinks that have access to the current source information. - /// - public interface IRoutingSinkWithCurrentSources : IRoutingSink, ICurrentSources - { - } -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs index c0fd03df..63f51953 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs @@ -1,25 +1,12 @@ -using PepperDash.Essentials.Core.Routing; -using System; -using System.Collections.Generic; +namespace PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core + + +/// +/// Defines the contract for IRoutingSinkWithFeedback +/// +public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching { - - /// - /// Defines the contract for IRoutingSinkWithFeedback - /// - public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching - { - - } -/* /// - /// For fixed-source endpoint devices - /// - public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching - { - RouteSwitchDescriptor CurrentRoute { get; } +} - event EventHandler InputChanged; - }*/ -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs index 5c202914..88e1f72b 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs @@ -1,43 +1,30 @@ -using System; + +namespace PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core +/// +/// Delegate for InputChangedEventHandler +/// +public delegate void InputChangedEventHandler(IRoutingSinkWithSwitching destination, RoutingInputPort currentPort); + +/// +/// Defines the contract for IRoutingSinkWithSwitching +/// +public interface IRoutingSinkWithSwitching : IRoutingSink { /// - /// Delegate for InputChangedEventHandler + /// Executes a switch on the device /// - public delegate void InputChangedEventHandler(IRoutingSinkWithSwitching destination, RoutingInputPort currentPort); + /// input selector + void ExecuteSwitch(object inputSelector); +} +/// +/// Defines the contract for IRoutingSinkWithSwitchingWithInputPort +/// +public interface IRoutingSinkWithSwitchingWithInputPort : IRoutingSinkWithSwitching, IRoutingSinkWithInputPort +{ /// - /// Defines the contract for IRoutingSinkWithSwitching + /// Event raised when the input changes /// - 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); - }*/ -} \ No newline at end of file + event InputChangedEventHandler InputChanged; +} diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSlot.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSlot.cs index 2e8c544f..deb5cabe 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSlot.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSlot.cs @@ -1,9 +1,4 @@ using PepperDash.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace PepperDash.Essentials.Core.Routing { diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs index 75bf1bfb..5eaaabf8 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs @@ -1,9 +1,8 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Marker interface to identify a device that acts as the origin of a signal path (). +/// +public interface IRoutingSource : IRoutingOutputs { - /// - /// Defines the contract for IRoutingSource - /// - public interface IRoutingSource : IRoutingOutputs - { - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs index 2a80022d..dc027db9 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs @@ -1,15 +1,14 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines a routing device () that supports explicitly clearing a route on an output. +/// +public interface IRoutingWithClear : IRouting { /// - /// Defines the contract for IRoutingWithClear + /// Clears a route to an output, however a device needs to do that /// - 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); - } + /// Output to clear + /// signal type to clear + void ClearRoute(object outputSelector, eRoutingSignalType signalType); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs index e66084a7..6578ee4f 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs @@ -1,30 +1,29 @@ using System.Collections.Generic; using System; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Gets a list describing the currently active routes on this device. +/// +/// 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 { /// - /// Delegate for handling route change events on devices implementing . + /// Gets a list describing the currently active routes on this device. /// - /// 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; } + List CurrentRoutes { get; } - /// - /// Event triggered when a route changes on this device. - /// - event RouteChangedEventHandler RouteChanged; - } -} \ No newline at end of file + /// + /// Event triggered when a route changes on this device. + /// + event RouteChangedEventHandler RouteChanged; +} diff --git a/src/PepperDash.Essentials.Core/Routing/ITxRouting.cs b/src/PepperDash.Essentials.Core/Routing/ITxRouting.cs index 0bd818ac..67901117 100644 --- a/src/PepperDash.Essentials.Core/Routing/ITxRouting.cs +++ b/src/PepperDash.Essentials.Core/Routing/ITxRouting.cs @@ -1,17 +1,17 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a routing device (typically a transmitter or source) that provides numeric feedback for its current route. +/// Extends . +/// +public interface ITxRouting : IRoutingNumeric { /// - /// Defines the contract for ITxRouting + /// Feedback indicating the currently routed video source by its numeric identifier. /// - 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; } - } + IntFeedback VideoSourceNumericFeedback { get; } + /// + /// Feedback indicating the currently routed audio source by its numeric identifier. + /// + IntFeedback AudioSourceNumericFeedback { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs index abfbff7f..0ba49439 100644 --- a/src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs @@ -1,9 +1,8 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines an IRmcRouting with a feedback event +/// +public interface ITxRoutingWithFeedback : ITxRouting { - /// - /// Defines the contract for ITxRoutingWithFeedback - /// - public interface ITxRoutingWithFeedback : ITxRouting - { - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs b/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs index aab82d38..c69285dd 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs @@ -7,228 +7,208 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +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 { /// - /// Represents a collection of individual route steps between a Source and a Destination device for a specific signal type. + /// The destination device (sink or midpoint) for the route. /// - public class RouteDescriptor + public IRoutingInputs Destination { get; private set; } + + /// + /// The specific input port on the destination device used for this route. Can be null if not specified or applicable. + /// + public RoutingInputPort InputPort { get; private set; } + + /// + /// The source device for the route. + /// + public IRoutingOutputs Source { get; private set; } + + /// + /// The type of signal being routed (e.g., Audio, Video). This descriptor represents a single signal type. + /// + public eRoutingSignalType SignalType { get; private set; } + + /// + /// A list of individual switching steps required to establish the 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) { - /// - /// The destination device (sink or midpoint) for the route. - /// - public IRoutingInputs Destination { get; private set; } + } - /// - /// Gets or sets the InputPort - /// - public RoutingInputPort InputPort { get; private set; } + /// + /// 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) + { + Destination = destination; + InputPort = inputPort; + Source = source; + SignalType = signalType; + Routes = new List(); + } - /// - /// Gets or sets the Source - /// - public IRoutingOutputs Source { get; private set; } - - /// - /// Gets or sets the SignalType - /// - public eRoutingSignalType SignalType { get; private set; } - - /// - /// Gets or sets the Routes - /// - 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) + /// + /// Executes all the switching steps defined in the list. + /// + public void ExecuteRoutes() + { + foreach (var route in Routes) { - } + Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, route.ToString()); - /// - /// 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) - { - Destination = destination; - InputPort = inputPort; - Source = source; - SignalType = signalType; - Routes = new List(); - } - - /// - /// ExecuteRoutes method - /// - public void ExecuteRoutes() - { - foreach (var route in Routes) + if (route.SwitchingDevice is IRoutingSinkWithSwitching sink) { - Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, 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.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); - } + sink.ExecuteSwitch(route.InputPort.Selector); + continue; } - } - /// - /// 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 (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); - } - } + switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); - if (route.OutputPort == null) - { - continue; - } + route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType); - if (route.OutputPort.InUseTracker != null) - { - route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType); - Debug.LogMessage(LogEventLevel.Verbose, "Port {0} releasing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); - } - else - { - Debug.LogMessage(LogEventLevel.Error, "InUseTracker is null for OutputPort {0}", null, route.OutputPort.Key); - } - } + Debug.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); } } - - /// - /// 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 string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); - } } - /*/// - /// Represents an collection of individual route steps between Source and Destination - /// /// - /// Represents a RouteDescriptor + /// Releases the usage tracking for the route and optionally clears the route on the switching devices. /// - public class RouteDescriptor + /// If true, attempts to clear the route on the switching devices (e.g., set input to null/0). + public void ReleaseRoutes(bool clearRoute = false) { - /// - /// Gets or sets the Destination - /// - public IRoutingInputs Destination { get; private set; } - /// - /// Gets or sets the Source - /// - public IRoutingOutputs Source { get; private set; } - /// - /// Gets or sets the SignalType - /// - public eRoutingSignalType SignalType { get; private set; } - public List> Routes { get; private set; } - - - public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) + foreach (var route in Routes.Where(r => r.SwitchingDevice is IRouting)) { - Destination = destination; - Source = source; - SignalType = signalType; - Routes = new List>(); - } - - /// - /// ExecuteRoutes method - /// - public void ExecuteRoutes() - { - foreach (var route in Routes) + if (route.SwitchingDevice is IRouting switchingDevice) { - Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, route.ToString()); - - if (route.SwitchingDevice is IRoutingSinkWithSwitching sink) + if(clearRoute) + { + try + { + switchingDevice.ExecuteSwitch(null, route.OutputPort.Selector, SignalType); + } + catch (Exception e) + { + Debug.LogError("Error executing switch: {exception}", e.Message); + } + } + + if (route.OutputPort == null) { - sink.ExecuteSwitch(route.InputPort.Selector); continue; } - if (route.SwitchingDevice is IRouting switchingDevice) + if (route.OutputPort.InUseTracker != null) { - switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); - - route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType); - - Debug.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); - } - } - } - - /// - /// ReleaseRoutes method - /// - public void ReleaseRoutes() - { - foreach (var route in Routes) - { - if (route.SwitchingDevice is IRouting) - { - // Pull the route from the port. Whatever is watching the output's in use tracker is - // responsible for responding appropriately. route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType); Debug.LogMessage(LogEventLevel.Verbose, "Port {0} releasing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); } + else + { + Debug.LogMessage(LogEventLevel.Error, "InUseTracker is null for OutputPort {0}", null, route.OutputPort.Key); + } } } + } - /// - /// ToString method - /// - /// - public override string ToString() + /// + /// 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 string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); + } +} + +/*/// +/// Represents an collection of individual route steps between Source and Destination +/// +public class RouteDescriptor +{ + public IRoutingInputs Destination { get; private set; } + public IRoutingOutputs Source { get; private set; } + public eRoutingSignalType SignalType { get; private set; } + public List> Routes { get; private set; } + + + public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) + { + Destination = destination; + Source = source; + SignalType = signalType; + Routes = new List>(); + } + + /// + /// Executes all routes described in this collection. Typically called via + /// extension method IRoutingInputs.ReleaseAndMakeRoute() + /// + public void ExecuteRoutes() + { + foreach (var route in Routes) { - var routesText = Routes.Select(r => r.ToString()).ToArray(); - return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); + Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, 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.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); + } } - }*/ -} \ No newline at end of file + } + + /// + /// Releases all routes in this collection. Typically called via + /// extension method IRoutingInputs.ReleaseAndMakeRoute() + /// + public void ReleaseRoutes() + { + foreach (var route in Routes) + { + if (route.SwitchingDevice is IRouting) + { + // Pull the route from the port. Whatever is watching the output's in use tracker is + // responsible for responding appropriately. + route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType); + Debug.LogMessage(LogEventLevel.Verbose, "Port {0} releasing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); + } + } + } + + public override string ToString() + { + var routesText = Routes.Select(r => r.ToString()).ToArray(); + return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); + } +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs b/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs index 483ea22a..81f3aa6a 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs @@ -4,103 +4,90 @@ using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// A collection of RouteDescriptors - typically the static DefaultCollection is used +/// +public class RouteDescriptorCollection { - /// - /// A collection of RouteDescriptors - typically the static DefaultCollection is used - /// - public class RouteDescriptorCollection + public static RouteDescriptorCollection DefaultCollection { - /// - /// DefaultCollection static property - /// - public static RouteDescriptorCollection DefaultCollection + get { - get - { - if (_DefaultCollection == null) - _DefaultCollection = new RouteDescriptorCollection(); - return _DefaultCollection; - } - } - private static RouteDescriptorCollection _DefaultCollection; - - private readonly List RouteDescriptors = new List(); - - /// - /// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the - /// destination exists already, it will not be added - in order to preserve - /// proper route releasing. - /// - /// - public void AddRouteDescriptor(RouteDescriptor descriptor) - { - if (descriptor == null) - { - return; - } - - if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination) - && RouteDescriptors.Any(t => t.Destination == descriptor.Destination && t.InputPort != null && descriptor.InputPort != null && t.InputPort.Key == descriptor.InputPort.Key)) - { - Debug.LogMessage(LogEventLevel.Debug, descriptor.Destination, - "Route to [{0}] already exists in global routes table", descriptor?.Source?.Key); - return; - } - 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 RouteDescriptor for a destination and input port key. Returns null if no matching RouteDescriptor exists. - /// - /// - /// - /// - 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; + if (_DefaultCollection == null) + _DefaultCollection = new RouteDescriptorCollection(); + return _DefaultCollection; } } + private static RouteDescriptorCollection _DefaultCollection; + + private readonly List RouteDescriptors = new List(); - /*/// - /// A collection of RouteDescriptors - typically the static DefaultCollection is used - /// /// - /// Represents a RouteDescriptorCollection + /// 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 class RouteDescriptorCollection + /// + public void AddRouteDescriptor(RouteDescriptor descriptor) + { + if (descriptor == null) + { + return; + } + + if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination) + && RouteDescriptors.Any(t => t.Destination == descriptor.Destination && t.InputPort != null && descriptor.InputPort != null && t.InputPort.Key == descriptor.InputPort.Key)) + { + Debug.LogMessage(LogEventLevel.Debug, descriptor.Destination, + "Route to [{0}] already exists in global routes table", descriptor?.Source?.Key); + return; + } + RouteDescriptors.Add(descriptor); + } + + /// + /// Gets the RouteDescriptor for a destination + /// + /// null if no RouteDescriptor for a destination exists + public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination) + { + Debug.LogMessage(LogEventLevel.Information, "Getting route descriptor for '{destination}'", destination?.Key ?? null); + + return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination); + } + + 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); + } + + /// + /// Returns the RouteDescriptor for a given destination AND removes it from collection. + /// Returns null if no route with the provided destination exists. + /// + public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination, 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; + } +} + +/*/// +/// A collection of RouteDescriptors - typically the static DefaultCollection is used +/// +public class RouteDescriptorCollection { public static RouteDescriptorCollection DefaultCollection { @@ -158,5 +145,4 @@ namespace PepperDash.Essentials.Core RouteDescriptors.Remove(descr); return descr; } - }*/ -} \ No newline at end of file + }*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs b/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs index 30c0e5f8..08752257 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs @@ -2,77 +2,76 @@ using Serilog.Events; using System; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a request to establish a route between a source and a destination device. +/// +public class RouteRequest { /// - /// Represents a 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 class RouteRequest + public RoutingInputPort DestinationPort { get; set; } + + /// + /// The specific output port on the source device to use for the route. Can be null if the port should be automatically determined or is not applicable. + /// + public RoutingOutputPort SourcePort { get; set; } + + /// + /// The destination device (sink or midpoint) for the route. + /// + public IRoutingInputs Destination { get; set; } + + /// + /// The source device for the route. + /// + public IRoutingOutputs Source { get; set; } + + /// + /// The type of signal being routed (e.g., Audio, Video, AudioVideo). + /// + 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) { - /// - /// 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 { - 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) { - 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); + return; } - } - /// - /// Returns a string representation of the route request. - /// - /// A string describing the source and destination of the route request. - public override string ToString() + 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) { - return $"Route {Source?.Key ?? "No Source Device"}:{SourcePort?.Key ?? "auto"} to {Destination?.Key ?? "No Destination Device"}:{DestinationPort?.Key ?? "auto"}"; + 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"}"; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs b/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs index 812f1399..1f7ab486 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs @@ -3,87 +3,86 @@ using PepperDash.Essentials.Core.Queues; using System; using Serilog.Events; -namespace PepperDash.Essentials.Core.Routing +namespace PepperDash.Essentials.Core.Routing; + +/// +/// Represents an item in the route request queue. +/// +public class RouteRequestQueueItem : IQueueMessage { /// - /// Represents a RouteRequestQueueItem + /// The action to perform for the route request. /// - public class RouteRequestQueueItem : IQueueMessage + 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) { - /// - /// 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); - } + action = routeAction; + routeRequest = request; } /// - /// Represents a ReleaseRouteQueueItem + /// Dispatches the route request action. /// - public class ReleaseRouteQueueItem : IQueueMessage + public void Dispatch() { - /// - /// 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); - } + Debug.LogMessage(LogEventLevel.Information, "Dispatching route request {routeRequest}", null, routeRequest); + action(routeRequest); + } +} + +/// +/// Represents an item in the queue for releasing a route. +/// +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; + } + + /// + /// Dispatches the release route action. + /// + 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); } } diff --git a/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs b/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs index 12aebdcf..03759018 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs @@ -1,9 +1,9 @@ -namespace PepperDash.Essentials.Core -{ - /// - /// Represents a RouteSwitchDescriptor - /// - public class RouteSwitchDescriptor +namespace PepperDash.Essentials.Core; + +/// +/// Represents a single switching step within a larger route, detailing the switching device, input port, and optionally the output port. +/// +public class RouteSwitchDescriptor { /// /// Gets or sets the SwitchingDevice @@ -45,55 +45,10 @@ /// 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")}"; + 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")}"; } } - /*/// - /// Represents an individual link for a route - /// - /// - /// Represents a RouteSwitchDescriptor - /// - public class RouteSwitchDescriptor - { - /// - /// Gets or sets the SwitchingDevice - /// - public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } } - /// - /// Gets or sets the OutputPort - /// - public RoutingOutputPort OutputPort { get; set; } - /// - /// Gets or sets the InputPort - /// - public RoutingInputPort InputPort { get; set; } - - public RouteSwitchDescriptor(RoutingInputPort inputPort) - { - InputPort = inputPort; - } - - public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort) - { - InputPort = inputPort; - OutputPort = outputPort; - } - - /// - /// ToString method - /// - /// - public override string ToString() - { - if (SwitchingDevice is IRouting) - return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector); - else - return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector); - } - }*/ -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs index e37d2d57..152b245a 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs @@ -3,411 +3,307 @@ using System.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.Config; -namespace PepperDash.Essentials.Core.Routing +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 { /// - /// 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. + /// Initializes a new instance of the class. /// - public class RoutingFeedbackManager : EssentialsDevice + /// The unique key for this manager device. + /// The name of this manager device. + public RoutingFeedbackManager(string key, string name): base(key, name) + { + AddPreActivationAction(SubscribeForMidpointFeedback); + AddPreActivationAction(SubscribeForSinkFeedback); + } + + + /// + /// Subscribes to the RouteChanged event on all devices implementing . + /// + private void SubscribeForMidpointFeedback() { - /// - /// 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) + var midpointDevices = DeviceManager.AllDevices.OfType(); + + foreach (var device in midpointDevices) { - AddPreActivationAction(SubscribeForMidpointFeedback); - AddPreActivationAction(SubscribeForSinkFeedback); + device.RouteChanged += HandleMidpointUpdate; } + } - /// - /// 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(); + /// + /// 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. + /// Triggers an update for all sink devices. + /// + /// The midpoint device that reported a route change. + /// The descriptor of the new route. + private void HandleMidpointUpdate(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute) + { + try + { + var devices = DeviceManager.AllDevices.OfType(); + + foreach (var device in devices) + { + UpdateDestination(device, device.CurrentInputPort); } } - - /// - /// Handles the RouteChanged event from a midpoint device. - /// Triggers an update for all sink devices. - /// - /// The midpoint device that reported a route change. - /// The descriptor of the new route. - private void HandleMidpointUpdate( - IRoutingWithFeedback midpoint, - RouteSwitchDescriptor newRoute - ) + catch (Exception ex) { - try - { - var devices = - DeviceManager.AllDevices.OfType(); + Debug.LogMessage(ex, "Error handling midpoint update from {midpointKey}:{Exception}", this, midpoint.Key, ex); + } + } - foreach (var device in devices) - { - UpdateDestination(device, device.CurrentInputPort); - } - } - catch (Exception ex) - { - Debug.LogMessage( - ex, - "Error handling midpoint update from {midpointKey}:{Exception}", - this, - midpoint.Key, - ex - ); - } + /// + /// Handles the InputChanged event from a sink device. + /// Triggers an update for the specific sink device. + /// + /// 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 + { + 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. + /// + /// The destination sink device to update. + /// The currently selected input port on the destination device. + private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort) + { + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Updating destination {destination} with inputPort {inputPort}", this,destination?.Key, inputPort?.Key); + + if(inputPort == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "Destination {destination} has not reported an input port yet", this,destination.Key); + return; } - /// - /// Handles the InputChanged event from a sink device. - /// Triggers an update for the specific sink device. - /// - /// The sink device that reported an input change. - /// The new input port selected on the sink device. - private void HandleSinkUpdate( - IRoutingSinkWithSwitching sender, - RoutingInputPort currentInputPort - ) + TieLine firstTieLine; + try { - try + var tieLines = TieLineCollection.Default; + + firstTieLine = tieLines.FirstOrDefault(tl => tl.DestinationPort.Key == inputPort.Key && tl.DestinationPort.ParentDevice.Key == inputPort.ParentDevice.Key); + + if (firstTieLine == null) { - 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. - /// - /// The destination sink device to update. - /// The currently selected input port on the destination device. - private void UpdateDestination( - 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.LogMessage(ex, "Error getting sourceTieLine: {Exception}", this, ex); - 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; - } - - 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.LogMessage( - Serilog.Events.LogEventLevel.Debug, - "No source list found for source list key {key}. Unable to find source for tieLine {sourceTieLine}", - this, - 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.LogMessage( - Serilog.Events.LogEventLevel.Debug, - "No source found for device {key}. Creating transient source for {destination}", - this, - sourceTieLine.SourcePort.ParentDevice.Key, - destination - ); + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No tieline found for inputPort {inputPort}. Clearing current source", this, inputPort); var tempSourceListItem = new SourceListItem { SourceKey = "$transient", - Name = sourceTieLine.SourcePort.Key, + Name = inputPort.Key, }; + + destination.CurrentSourceInfo = tempSourceListItem; ; 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; + } catch (Exception ex) + { + Debug.LogMessage(ex, "Error getting first tieline: {Exception}", this, ex); + return; } - /// - /// Recursively traces a route back from a given tie line to find the root source tie line. - /// It navigates through midpoint devices () by checking their current routes. - /// - /// 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) + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Getting source for first TieLine {tieLine}", this, firstTieLine); + + TieLine sourceTieLine; + try { - TieLine nextTieLine = null; - try + sourceTieLine = GetRootTieLine(firstTieLine); + + if (sourceTieLine == null) { - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "**Following tieLine {tieLine}**", this, tieLine); + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route found to source for inputPort {inputPort}. Clearing current source", this, inputPort); - if (tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint) + var tempSourceListItem = new SourceListItem { - // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device {sourceDevice} is midpoint", this, midpoint); + SourceKey = "$transient", + Name = "None", + }; - if (midpoint.CurrentRoutes == null || midpoint.CurrentRoutes.Count == 0) - { - Debug.LogMessage( - Serilog.Events.LogEventLevel.Debug, - "Midpoint {midpointKey} has no routes", - this, - midpoint.Key - ); - return null; - } + destination.CurrentSourceInfo = tempSourceListItem; + destination.CurrentSourceInfoKey = string.Empty; + return; + } + } catch(Exception ex) + { + Debug.LogMessage(ex, "Error getting sourceTieLine: {Exception}", this, ex); + return; + } - var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => - { - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", this, route, tieLine); + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine); - return route.OutputPort != null - && route.InputPort != null - && route.OutputPort?.Key == tieLine.SourcePort.Key - && route.OutputPort?.ParentDevice.Key - == tieLine.SourcePort.ParentDevice.Key; - }); + // 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 (currentRoute == null) - { - Debug.LogMessage( - Serilog.Events.LogEventLevel.Debug, - "No route through midpoint {midpoint} for outputPort {outputPort}", - this, - midpoint.Key, - tieLine.SourcePort - ); - return null; - } + if(r is IHasDefaultDisplay roomDefaultDisplay) + { + return roomDefaultDisplay.DefaultDisplay.Key == destination.Key; + } - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found currentRoute {currentRoute} through {midpoint}", this, currentRoute, midpoint); + return false; + }); + + if(room == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "No room found for display {destination}", this, destination.Key); + return; + } - nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => - { - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", tl.DestinationPort.Key, currentRoute.InputPort.Key); - return tl.DestinationPort.Key == currentRoute.InputPort.Key - && tl.DestinationPort.ParentDevice.Key - == currentRoute.InputPort.ParentDevice.Key; - }); + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found room {room} for destination {destination}", this, room.Key, destination.Key); - if (nextTieLine != null) - { - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found next tieLine {tieLine}. Walking the chain", this, nextTieLine); - return GetRootTieLine(nextTieLine); - } + var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey); - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root tieLine {tieLine}", this,nextTieLine); - return nextTieLine; + if (sourceList == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "No source list found for source list key {key}. Unable to find source for tieLine {sourceTieLine}", this, 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.LogMessage(Serilog.Events.LogEventLevel.Information, "No source found for device {key}. Creating transient source for {destination}", this, 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; + + } + + /// + /// Recursively traces a route back from a given tie line to find the root source tie line. + /// It navigates through midpoint devices () by checking their current routes. + /// + /// 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) + { + TieLine nextTieLine = null; + try + { + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "**Following tieLine {tieLine}**", this, tieLine); + + if (tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint) + { + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device {sourceDevice} is midpoint", this, midpoint); + + if(midpoint.CurrentRoutes == null || midpoint.CurrentRoutes.Count == 0) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Midpoint {midpointKey} has no routes",this, midpoint.Key); + return null; } - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLIne Source Device {sourceDeviceKey} is IRoutingSource: {isIRoutingSource}", this, tieLine.SourcePort.ParentDevice.Key, tieLine.SourcePort.ParentDevice is IRoutingSource); - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source Device interfaces: {typeFullName}:{interfaces}", this, tieLine.SourcePort.ParentDevice.GetType().FullName, tieLine.SourcePort.ParentDevice.GetType().GetInterfaces().Select(i => i.Name)); + var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => { + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", this, route, tieLine); - if ( - tieLine.SourcePort.ParentDevice is IRoutingSource - || tieLine.SourcePort.ParentDevice is IRoutingOutputs - ) //end of the chain + return route.OutputPort != null && route.InputPort != null && route.OutputPort?.Key == tieLine.SourcePort.Key && route.OutputPort?.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key; + }); + + if (currentRoute == null) { - // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine); - return tieLine; + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route through midpoint {midpoint} for outputPort {outputPort}", this, midpoint.Key, tieLine.SourcePort); + return null; } - nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => - tl.DestinationPort.Key == tieLine.SourcePort.Key - && tl.DestinationPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key - ); + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found currentRoute {currentRoute} through {midpoint}", this, currentRoute, midpoint); + + nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => { + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", tl.DestinationPort.Key, currentRoute.InputPort.Key); + return tl.DestinationPort.Key == currentRoute.InputPort.Key && tl.DestinationPort.ParentDevice.Key == currentRoute.InputPort.ParentDevice.Key; }); if (nextTieLine != null) { + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found next tieLine {tieLine}. Walking the chain", this, nextTieLine); return GetRootTieLine(nextTieLine); } - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Error walking tieLines: {Exception}", this, ex); - return null; + + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root tieLine {tieLine}", this,nextTieLine); + return nextTieLine; } + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLIne Source Device {sourceDeviceKey} is IRoutingSource: {isIRoutingSource}", this, tieLine.SourcePort.ParentDevice.Key, tieLine.SourcePort.ParentDevice is IRoutingSource); + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source Device interfaces: {typeFullName}:{interfaces}", this, tieLine.SourcePort.ParentDevice.GetType().FullName, tieLine.SourcePort.ParentDevice.GetType().GetInterfaces().Select(i => i.Name)); + + if (tieLine.SourcePort.ParentDevice is IRoutingSource || tieLine.SourcePort.ParentDevice is IRoutingOutputs) //end of the chain + { + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine); + return tieLine; + } + + nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == tieLine.SourcePort.Key && tl.DestinationPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key ); + + if (nextTieLine != null) + { + return GetRootTieLine(nextTieLine); + } + } catch (Exception ex) + { + Debug.LogMessage(ex, "Error walking tieLines: {Exception}", this, ex); return null; } + + return null; } } diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs index 4e50f689..fbc575e9 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs @@ -2,18 +2,18 @@ using System; -namespace PepperDash.Essentials.Core -{ - /// - /// Represents a RoutingInputPort - /// - public class RoutingInputPort : RoutingPort +namespace PepperDash.Essentials.Core; + +/// +/// Represents a basic routing input port on a device. +/// +public class RoutingInputPort : RoutingPort { - /// - /// The IRoutingInputs object this lives on - /// - [JsonIgnore] - public IRoutingInputs ParentDevice { get; private set; } + /// + /// The IRoutingInputs object this lives on + /// + [JsonIgnore] + public IRoutingInputs ParentDevice { get; private set; } /// /// Constructor for a basic RoutingInputPort @@ -50,49 +50,13 @@ namespace PepperDash.Essentials.Core 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. + /// + /// Returns a string representation of the input port. /// - public class RoutingInputPort : RoutingPort + /// A string in the format "ParentDeviceKey|PortKey|SignalType|ConnectionType". + public override string ToString() { - /// - /// Gets or sets the ParentDevice - /// - public IRoutingInputs ParentDevice { get; private set; } + return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}"; + } +} - /// - /// 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)); - } - }*/ -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs b/src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs index 2ecf75c4..d98c1ae3 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs @@ -1,30 +1,30 @@ -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; } +namespace PepperDash.Essentials.Core; - /// - /// 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); - } +/// +/// Represents a routing input port that provides video status feedback (e.g., sync, resolution). +/// Suitable for devices like DM transmitters or DM input cards. +/// +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); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs b/src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs index a2025dad..89cd3d5c 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs @@ -1,83 +1,82 @@ using System; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Provides event arguments for routing changes, potentially including numeric or port object references. +/// +public class RoutingNumericEventArgs : EventArgs { /// - /// Represents a RoutingNumericEventArgs + /// The numeric representation of the output, if applicable. /// - public class RoutingNumericEventArgs : EventArgs + 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) { - /// - /// 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 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 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 with default values. + /// + public RoutingNumericEventArgs() + : this(null, null, null, null, 0) + { - /// - /// 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; - /// - /// 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; - } + Output = output; + Input = input; + SigType = sigType; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs index c1cadfb1..747106ce 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs @@ -2,105 +2,63 @@ using System; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a basic routing output port on a device. +/// +public class RoutingOutputPort : RoutingPort { /// /// Represents a RoutingOutputPort /// - public class RoutingOutputPort : RoutingPort + [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) { - /// - /// 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 + /// + /// 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) { - /// - /// Gets or sets the ParentDevice - /// - public IRoutingOutputs ParentDevice { get; private set; } + ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); + InUseTracker = new InUseTracking(); + } - /// - /// Gets or sets the InUseTracker - /// - public InUseTracking InUseTracker { get; private set; } + /// + /// 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}"; + } +} - - /// - /// - /// 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; - } - }*/ -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs index 30440578..7fa01811 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs @@ -1,12 +1,12 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ - /// - /// Base class for and . - /// - public abstract class RoutingPort : IKeyed +namespace PepperDash.Essentials.Core; + +/// +/// Base class for and . +/// +public abstract class RoutingPort : IKeyed { /// /// The unique key identifying this port within its parent device. @@ -28,14 +28,14 @@ namespace PepperDash.Essentials.Core /// 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; } + /// + /// 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. @@ -53,43 +53,5 @@ namespace PepperDash.Essentials.Core 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; - } - }*/ -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs b/src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs index 7ee349b5..736d507f 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.Core -{ +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. /// @@ -20,21 +20,3 @@ namespace PepperDash.Essentials.Core } } } - -/* /// - /// 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)); - } - } - }*/ -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs b/src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs index 96a2ca32..a783a0b0 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs @@ -4,249 +4,248 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +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. +/// These should correspond directly with the portNames var in the config tool. /// public class RoutingPortNames { - /// - /// antennaIn - /// + /// + /// antennaIn + /// public const string AntennaIn = "antennaIn"; - /// - /// anyAudioIn - /// + /// + /// anyAudioIn + /// public const string AnyAudioIn = "anyAudioIn"; - /// - /// anyAudioOut - /// + /// + /// anyAudioOut + /// public const string AnyAudioOut = "anyAudioOut"; - /// - /// anyOut - /// - public const string AnyOut = "anyOut"; - /// - /// anyVideoIn - /// - public const string AnyVideoIn = "anyVideoIn"; - /// - /// anyVideoOut - /// + /// + /// anyOut + /// + public const string AnyOut = "anyOut"; + /// + /// anyVideoIn + /// + public const string AnyVideoIn = "anyVideoIn"; + /// + /// anyVideoOut + /// public const string AnyVideoOut = "anyVideoOut"; - /// - /// balancedAudioOut - /// + /// + /// balancedAudioOut + /// public const string BalancedAudioOut = "balancedAudioOut"; - /// - /// codecOsd - /// - public const string CodecOsd = "codecOsd"; - /// - /// componentIn - /// + /// + /// codecOsd + /// + public const string CodecOsd = "codecOsd"; + /// + /// componentIn + /// public const string ComponentIn = "componentIn"; - /// - /// componentOut - /// + /// + /// componentOut + /// public const string ComponentOut = "componentOut"; - /// - /// compositeIn - /// + /// + /// compositeIn + /// public const string CompositeIn = "compositeIn"; - /// - /// compositeOut - /// + /// + /// compositeOut + /// public const string CompositeOut = "compositeOut"; - /// - /// displayPortIn - /// + /// + /// displayPortIn + /// public const string DisplayPortIn = "displayPortIn"; - /// - /// displayPortIn1 - /// + /// + /// displayPortIn1 + /// public const string DisplayPortIn1 = "displayPortIn1"; - /// - /// displayPortIn2 - /// + /// + /// displayPortIn2 + /// public const string DisplayPortIn2 = "displayPortIn2"; - /// - /// displayPortIn3 - /// + /// + /// displayPortIn3 + /// public const string DisplayPortIn3 = "displayPortIn3"; - /// - /// displayPortOut - /// + /// + /// displayPortOut + /// public const string DisplayPortOut = "displayPortOut"; - /// - /// dmIn - /// + /// + /// dmIn + /// public const string DmIn = "dmIn"; - /// - /// dmOut - /// + /// + /// dmOut + /// public const string DmOut = "dmOut"; - /// - /// dviIn - /// + /// + /// dviIn + /// public const string DviIn = "dviIn"; - /// - /// dviIn1 - /// - public const string DviIn1 = "dviIn1"; - /// - /// dviOut - /// - public const string DviOut = "dviOut"; - /// - /// hdmiIn - /// + /// + /// dviIn1 + /// + public const string DviIn1 = "dviIn1"; + /// + /// dviOut + /// + public const string DviOut = "dviOut"; + /// + /// hdmiIn + /// public const string HdmiIn = "hdmiIn"; - /// - /// hdmiIn1 - /// + /// + /// hdmiIn1 + /// public const string HdmiIn1 = "hdmiIn1"; - /// - /// hdmiIn1PC - /// - public const string HdmiIn1PC = "hdmiIn1PC"; - /// - /// hdmiIn2 - /// + /// + /// hdmiIn1PC + /// + public const string HdmiIn1PC = "hdmiIn1PC"; + /// + /// hdmiIn2 + /// public const string HdmiIn2 = "hdmiIn2"; - /// - /// hdmiIn2PC - /// - public const string HdmiIn2PC = "hdmiIn2PC"; - /// - /// hdmiIn3 - /// + /// + /// hdmiIn2PC + /// + public const string HdmiIn2PC = "hdmiIn2PC"; + /// + /// hdmiIn3 + /// public const string HdmiIn3 = "hdmiIn3"; - /// - /// hdmiIn4 - /// + /// + /// hdmiIn4 + /// public const string HdmiIn4 = "hdmiIn4"; - /// - /// hdmiIn5 - /// + /// + /// hdmiIn5 + /// public const string HdmiIn5 = "hdmiIn5"; - /// - /// hdmiIn6 - /// + /// + /// hdmiIn6 + /// public const string HdmiIn6 = "hdmiIn6"; - /// - /// hdmiOut - /// + /// + /// 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 - /// + /// + /// 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 - /// + /// + /// 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 - /// + /// + /// 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"; - } + /// + /// 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"; } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/TieLine.cs b/src/PepperDash.Essentials.Core/Routing/TieLine.cs index 42f024b4..8b2f8863 100644 --- a/src/PepperDash.Essentials.Core/Routing/TieLine.cs +++ b/src/PepperDash.Essentials.Core/Routing/TieLine.cs @@ -2,154 +2,152 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a connection (tie line) between a and a . +/// +public class TieLine { /// /// 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. Will either be the type of the destination port - /// or the type of OverrideType when it is set. - /// - public eRoutingSignalType Type - { - get - { - if (OverrideType.HasValue) return OverrideType.Value; - return DestinationPort.Type; - } - } - - /// - /// Use this to override the Type property for the destination port. For example, - /// when the tie line is type AudioVideo, and the signal flow should be limited to - /// Audio-only or Video only, changing this type will alter the signal paths - /// available to the routing algorithm without affecting the actual Type - /// of the destination port. - /// - 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 DestinationPort.Type 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 DestinationPort.Type 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()); - } - } - - //******************************************************************************** + 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; } } /// /// 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 + public eRoutingSignalType Type { - /// - /// Gets the default singleton instance of the . - /// - public static TieLineCollection Default + get { - get - { - if (_Default == null) - _Default = new TieLineCollection(); - return _Default; - } + if (OverrideType.HasValue) return OverrideType.Value; + return DestinationPort.Type; } - - /// - /// Backing field for the singleton instance. - /// - [JsonIgnore] - private static TieLineCollection _Default; } + + /// + /// Use this to override the Type property for the destination port. For example, + /// when the tie line is type AudioVideo, and the signal flow should be limited to + /// Audio-only or Video only, changing this type will alter the signal paths + /// available to the routing algorithm without affecting the actual Type + /// of the destination port. + /// + 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 DestinationPort.Type 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 DestinationPort.Type 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. +/// +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; } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs b/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs index 156b39b1..3ea456d3 100644 --- a/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs +++ b/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs @@ -11,8 +11,8 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Config -{ +namespace PepperDash.Essentials.Core.Config; + /// /// Represents the configuration data for a single tie line between two routing ports. /// @@ -116,5 +116,4 @@ namespace PepperDash.Essentials.Core.Config { return $"{SourceKey}.{SourceCard}.{SourcePort} --> {DestinationKey}.{DestinationCard}.{DestinationPort}"; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs b/src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs index 9245dd48..33332856 100644 --- a/src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs +++ b/src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs @@ -100,4 +100,4 @@ /// HdBaseT } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs b/src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs index 9fce9c5b..e3d679da 100644 --- a/src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs +++ b/src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs @@ -39,4 +39,4 @@ namespace PepperDash.Essentials.Core /// SecondaryAudio = 32 } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Core/Secrets/CrestronGlobalSecretsProvider.cs b/src/PepperDash.Essentials.Core/Secrets/CrestronGlobalSecretsProvider.cs index 45983b0c..d89efd2c 100644 --- a/src/PepperDash.Essentials.Core/Secrets/CrestronGlobalSecretsProvider.cs +++ b/src/PepperDash.Essentials.Core/Secrets/CrestronGlobalSecretsProvider.cs @@ -5,115 +5,97 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class CrestronGlobalSecretsProvider : ISecretProvider { - /// - /// Represents a CrestronGlobalSecretsProvider - /// - public class CrestronGlobalSecretsProvider : ISecretProvider + public string Key { get; set; } + //Added for reference + public string Description { get; private set; } + + public CrestronGlobalSecretsProvider(string key) { - /// - /// Gets or sets the Key - /// - public string Key { get; set; } - //Added for reference - /// - /// Gets or sets the Description - /// - public string Description { get; private set; } + Key = key; + Description = String.Format("Default secret provider serving all local applications"); - /// - /// Constructor for CrestronGlobalSecretsProvider - /// - /// The key for the secret provider - public CrestronGlobalSecretsProvider(string key) + } + + static CrestronGlobalSecretsProvider() + { + //Added for future encrypted reference + var secureSupported = CrestronSecureStorage.Supported; + + CrestronDataStoreStatic.InitCrestronDataStore(); + if (secureSupported) { - 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; + //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; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Secrets/CrestronLocalSecretsProvider.cs b/src/PepperDash.Essentials.Core/Secrets/CrestronLocalSecretsProvider.cs index 31a1faa3..0bffd23e 100644 --- a/src/PepperDash.Essentials.Core/Secrets/CrestronLocalSecretsProvider.cs +++ b/src/PepperDash.Essentials.Core/Secrets/CrestronLocalSecretsProvider.cs @@ -6,117 +6,97 @@ using Crestron.SimplSharpPro; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class CrestronLocalSecretsProvider : ISecretProvider { - /// - /// Represents a CrestronLocalSecretsProvider - /// - public class CrestronLocalSecretsProvider : ISecretProvider + public string Key { get; set; } + //Added for reference + public string Description { get; private set; } + + + public CrestronLocalSecretsProvider(string key) { - /// - /// Gets or sets the Key - /// - public string Key { get; set; } - //Added for reference - /// - /// Gets or sets the Description - /// - public string Description { get; private set; } + Key = key; + Description = String.Format("Default secret provider serving Essentials Application {0}", InitialParametersClass.ApplicationNumber); + } - /// - /// Constructor for CrestronLocalSecretsProvider - /// - /// The key for the secret provider - public CrestronLocalSecretsProvider(string key) + static CrestronLocalSecretsProvider() + { + //Added for future encrypted reference + var secureSupported = CrestronSecureStorage.Supported; + + CrestronDataStoreStatic.InitCrestronDataStore(); + if (secureSupported) { - 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; + //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 + 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 + public bool TestSecret(string key) + { + string mySecret; + return CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret) == CrestronDataStore.CDS_ERROR.CDS_SUCCESS; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Secrets/CrestronSecret.cs b/src/PepperDash.Essentials.Core/Secrets/CrestronSecret.cs index 5a606453..1b628a44 100644 --- a/src/PepperDash.Essentials.Core/Secrets/CrestronSecret.cs +++ b/src/PepperDash.Essentials.Core/Secrets/CrestronSecret.cs @@ -4,41 +4,23 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Special container class for CrestronSecret provider +/// +public class CrestronSecret : ISecret { - /// - /// Special container class for CrestronSecret provider - /// - public class CrestronSecret : ISecret + public ISecretProvider Provider { get; private set; } + public string Key { get; private set; } + + public object Value { get; private set; } + + public CrestronSecret(string key, string value, ISecretProvider provider) { - /// - /// 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; - } - + Key = key; + Value = value; + Provider = provider; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Secrets/Interfaces.cs b/src/PepperDash.Essentials.Core/Secrets/Interfaces.cs index 55ce5ccc..f0b7fd38 100644 --- a/src/PepperDash.Essentials.Core/Secrets/Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Secrets/Interfaces.cs @@ -1,58 +1,57 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// All ISecrecretProvider classes must implement this interface. +/// +public interface ISecretProvider : IKeyed { /// - /// Defines the contract for ISecretProvider + /// Set secret value for provider by key /// - 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; } - } + /// key of secret to set + /// value to set secret to + /// + bool SetSecret(string key, object value); /// - /// interface for delivering secrets in Essentials. + /// Return object containing secret from provider /// - public interface ISecret - { - /// - /// Instance of ISecretProvider that the secret belongs to - /// - ISecretProvider Provider { get; } + /// key of secret to retrieve + /// + ISecret GetSecret(string key); - /// - /// Key of the secret in the provider - /// - string Key { get; } + /// + /// Verifies presence of secret + /// + /// key of secret to chek + /// + bool TestSecret(string key); - /// - /// Value of the secret - /// - object Value { get; } - } + /// + /// 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; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Secrets/SecretsManager.cs b/src/PepperDash.Essentials.Core/Secrets/SecretsManager.cs index 382f5d55..f35866fd 100644 --- a/src/PepperDash.Essentials.Core/Secrets/SecretsManager.cs +++ b/src/PepperDash.Essentials.Core/Secrets/SecretsManager.cs @@ -5,24 +5,19 @@ using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public static class SecretsManager { + public static Dictionary Secrets { get; private set; } + /// - /// SecretsManager static class + /// Initialize the SecretsManager /// - public static class SecretsManager + public static void Initialize() { - /// - /// Gets the Secrets dictionary - /// - public static Dictionary Secrets { get; private set; } - - /// - /// Initialize method - /// - public static void Initialize() + try { - AddSecretProvider("default", new CrestronLocalSecretsProvider("default")); AddSecretProvider("CrestronGlobalSecrets", new CrestronGlobalSecretsProvider("CrestronGlobalSecrets")); @@ -47,351 +42,338 @@ namespace PepperDash.Essentials.Core "Return data about secrets provider", ConsoleAccessLevelEnum.AccessAdministrator); } - - static SecretsManager() + catch (Exception e) { - 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; - - + Debug.LogError(e, "SecretsManager Initialize failed"); } } + static SecretsManager() + { + Secrets = new Dictionary(); + } + /// + /// Get Secret Provider from dictionary by key + /// + /// Dictionary Key for provider + /// ISecretProvider + 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; + } + + 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. + /// + /// + 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 + 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 + 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; + + + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Secrets/SecretsPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Secrets/SecretsPropertiesConfig.cs index a5a76074..b447851a 100644 --- a/src/PepperDash.Essentials.Core/Secrets/SecretsPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Secrets/SecretsPropertiesConfig.cs @@ -7,23 +7,15 @@ 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; } +namespace PepperDash.Essentials.Core; - /// - /// Gets or sets the Key - /// - [JsonProperty("key")] - public string Key { get; set; } - } +/// +/// Provide a way to easily deserialize into a secret object from config +/// +public class SecretsPropertiesConfig +{ + [JsonProperty("provider")] + public string Provider { get; set; } + [JsonProperty("key")] + public string Key { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Shades/Shade Interfaces.cs b/src/PepperDash.Essentials.Core/Shades/Shade Interfaces.cs index 2fb5ffd7..08abeaa8 100644 --- a/src/PepperDash.Essentials.Core/Shades/Shade Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Shades/Shade Interfaces.cs @@ -1,178 +1,177 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core.Shades +namespace PepperDash.Essentials.Core.Shades; + +/// +/// Defines the contract for IShades +/// +public interface IShades { - /// - /// Defines the contract for IShades - /// - public interface IShades - { - /// - /// List of shades controlled by this device - /// - List Shades { get; } - } + /// + /// 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 basic Open/Close/Stop shade control (Uses 3 relays) +/// +public interface IShadesOpenCloseStop +{ + /// + /// Opens the shade + /// + void Open(); /// - /// Requirements for a device that implements Open/Close/Stop shade control with presets + /// Closes the shade /// - 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; } - } + void Close(); /// - /// Requirements for a shade/scene that is open or closed + /// Stops the shade /// - public interface IShadesOpenClosedFeedback: IShadesOpenCloseStop - { - /// - /// Feedback to indicate if the shade is open - /// - BoolFeedback ShadeIsOpenFeedback { get; } + void Stop(); +} - /// - /// Feedback to indicate if the shade is closed - /// - BoolFeedback ShadeIsClosedFeedback { get; } - } +/// +/// 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); /// - /// Used to implement raise/stop/lower/stop from single button + /// Saves the preset /// - 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); - } + /// preset number to save + void SavePreset(uint presetNumber); /// - /// Basic feedback for shades position + /// Label for the preset button /// - public interface IShadesFeedback: IShadesPosition, IShadesStopFeedback - { - /// - /// Feedback to indicate the current position of the shade - /// - IntFeedback PositionFeedback { get; } - } + string StopOrPresetButtonLabel { get; } /// - /// Feedback for scenes + /// Event raised when a preset is recalled /// - public interface ISceneFeedback - { - /// - /// Runs the scene - /// - void Run(); + event EventHandler PresetSaved; +} - /// - /// Feedback to indicate if all shades are at the scene position - /// - BoolFeedback AllAreAtSceneFeedback { get; } - } + +/// +/// Defines the contract for IShadesRaiseLowerFeedback +/// +public interface IShadesRaiseLowerFeedback +{ + /// + /// Feedback to indicate if the shade is lowering + /// + BoolFeedback ShadeIsLoweringFeedback { get; } /// - /// Combines basic shade interfaces for Crestron Basic shades + /// Feedback to indicate if the shade is raising /// - public interface ICrestronBasicShade : IShadesOpenClosedFeedback, - IShadesStopOrMove, IShadesFeedback, IShadesRaiseLowerFeedback - { + BoolFeedback ShadeIsRaisingFeedback { get; } +} - } -} \ No newline at end of file +/// +/// 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 +{ + +} diff --git a/src/PepperDash.Essentials.Core/Shades/ShadeBase.cs b/src/PepperDash.Essentials.Core/Shades/ShadeBase.cs index ce5de98d..c0808989 100644 --- a/src/PepperDash.Essentials.Core/Shades/ShadeBase.cs +++ b/src/PepperDash.Essentials.Core/Shades/ShadeBase.cs @@ -7,42 +7,42 @@ using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core.CrestronIO; -namespace PepperDash.Essentials.Core.Shades +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 { /// - /// Base class for shades + /// Constructor /// - [Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")] - public abstract class ShadeBase : EssentialsDevice, IShadesOpenCloseStop + /// key of the shade device + /// name of the shade device + public ShadeBase(string key, string name) + : base(key, name) { - /// - /// 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 } -} \ No newline at end of file + + #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 +} + diff --git a/src/PepperDash.Essentials.Core/SigHelper.cs b/src/PepperDash.Essentials.Core/SigHelper.cs index df1ad605..3aa1bbc8 100644 --- a/src/PepperDash.Essentials.Core/SigHelper.cs +++ b/src/PepperDash.Essentials.Core/SigHelper.cs @@ -7,8 +7,8 @@ using Crestron.SimplSharpPro; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Helper class for various Sig events /// @@ -75,5 +75,4 @@ namespace PepperDash.Essentials.Core { sig.CreateRamp(level, time / 10); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDPad.cs b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDPad.cs index 605b2344..011b3f97 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDPad.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDPad.cs @@ -6,46 +6,45 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core.SmartObjects +namespace PepperDash.Essentials.Core.SmartObjects; + +/// +/// Represents a SmartObjectDPad +/// +public class SmartObjectDPad : SmartObjectHelperBase { - /// - /// Represents a SmartObjectDPad - /// - public class SmartObjectDPad : SmartObjectHelperBase - { - /// - /// Gets or sets the SigUp - /// - public BoolOutputSig SigUp { get { return GetBoolOutputNamed("Up"); } } + /// + /// 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 SigDown + /// + public BoolOutputSig SigDown { get { return GetBoolOutputNamed("Down"); } } - /// - /// Gets or sets the SigLeft - /// - public BoolOutputSig SigLeft { get { return GetBoolOutputNamed("Left"); } } + /// + /// 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 SigRight + /// + public BoolOutputSig SigRight { get { return GetBoolOutputNamed("Right"); } } - /// - /// Gets or sets the SigCenter - /// - public BoolOutputSig SigCenter { get { return GetBoolOutputNamed("Center"); } } + /// + /// 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) - { - } - } + /// + /// Constructor + /// + /// smart object + /// use user object handler if true + public SmartObjectDPad(SmartObject so, bool useUserObjectHandler) + : base(so, useUserObjectHandler) + { + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDynamicList.cs b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDynamicList.cs index fdf7dc04..d83d3aa5 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDynamicList.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDynamicList.cs @@ -1,153 +1,148 @@ 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 +namespace PepperDash.Essentials.Core.SmartObjects; + +/// +/// Represents a SmartObjectDynamicList +/// +public class SmartObjectDynamicList : SmartObjectHelperBase { - /// - /// 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 { - /// - /// 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 { - get - { - return SmartObject.UShortInput[SigNameSetNumberOfItems].UShortValue; - } - set { SmartObject.UShortInput[SigNameSetNumberOfItems].UShortValue = value; } + return SmartObject.UShortInput[SigNameSetNumberOfItems].UShortValue; } + set { SmartObject.UShortInput[SigNameSetNumberOfItems].UShortValue = value; } + } - /// - /// Gets or sets the MaxCount - /// - public int MaxCount { get; private set; } + /// + /// 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) + /// + /// 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 { - 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()); - //} + // 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); } - - /// - /// SetItemMainText method - /// - public void SetItemMainText(uint index, string text) + catch { - 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; + 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; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectHelperBase.cs b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectHelperBase.cs index a86687aa..aca01f2c 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectHelperBase.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectHelperBase.cs @@ -9,96 +9,91 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.SmartObjects +namespace PepperDash.Essentials.Core.SmartObjects; +/// +/// Represents a SmartObjectHelperBase +/// +public class SmartObjectHelperBase { /// - /// Represents a SmartObjectHelperBase + /// Gets or sets the SmartObject /// - public class SmartObjectHelperBase + 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) { - /// - /// 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 = so; + if (useUserObjectHandler) { + // Prevent this from double-registering SmartObject.SigChange -= this.SmartObject_SigChange; + 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); - } - } + + /// + /// 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. + /// + /// + /// + 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); + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectNumeric.cs b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectNumeric.cs index 2b6e06b8..8dbd1998 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectNumeric.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectNumeric.cs @@ -6,92 +6,94 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core.SmartObjects +namespace PepperDash.Essentials.Core.SmartObjects; + +/// +/// Represents a SmartObjectNumeric +/// This is a helper for a numeric keypad. It has the digits 0-9 and two miscellaneous buttons. The Misc1SigName and Misc2SigName can be set to whatever the user wants, but default to "Misc_1" and "Misc_2". +/// +public class SmartObjectNumeric : SmartObjectHelperBase { /// - /// Represents a SmartObjectNumeric + /// Defaults to "Misc_1". The name of the button in VTPro (Usually the text) /// - public class SmartObjectNumeric : SmartObjectHelperBase + 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) { - /// - /// 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"; - } + Misc1SigName = "Misc_1"; + Misc2SigName = "Misc_2"; } -} \ No newline at end of file +} + diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs b/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs index 4ed42d49..d7a5c839 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs @@ -1,305 +1,290 @@ - -using System; +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; -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 SubpageReferenceList { - ////***************************************************************************** - ///// - ///// 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. + /// Gets or sets the Count /// - public class SubpageReferenceList + public ushort Count { - /// - /// 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) { - get { return SetNumberOfItemsSig.UShortValue; } - set { SetNumberOfItemsSig.UShortValue = value; } + Debug.LogMessage(LogEventLevel.Information, "TriList {0:X2} Smart objects have not been loaded", triList.ID, smartObjectId); + return; } - - /// - /// 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) + if (triList.SmartObjects.TryGetValue(smartObjectId, out obj)) { - 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; + 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); + // 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); + 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); - } + /// + /// 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; + /// + /// 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; - } + ScrollToItemSig.UShortValue = 1; + } - /// - /// Refresh method - /// - public void Refresh() - { - foreach (var item in Items) item.Refresh(); - } + /// + /// Refresh method + /// + public void Refresh() + { + foreach (var item in Items) item.Refresh(); + } - // Helpers to get sigs by their weird SO names + // 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 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 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 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 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 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))); - } + /// + /// 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 + // Helpers to get signal names - string GetBoolFeedbackSigName(uint index, uint sigNum) - { - var num = (index - 1) * BoolIncrement + sigNum; - return String.Format("press{0}", num); - } + 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 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 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 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 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); - } + 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); - } + /// + /// 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); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceListItem.cs b/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceListItem.cs index e29d0894..878db77c 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceListItem.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceListItem.cs @@ -1,50 +1,41 @@ -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; -namespace PepperDash.Essentials.Core +/// +/// Represents a SubpageReferenceListItem +/// +public class SubpageReferenceListItem { - /// - /// 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) { - /// - /// 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() { } + Index = index; + Owner = owner; } + + /// + /// Clear method + /// + /// + public virtual void Clear() + { + } + + /// + /// Refresh method + /// + public virtual void Refresh() { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Timers/CountdownTimer.cs b/src/PepperDash.Essentials.Core/Timers/CountdownTimer.cs index 24ff6a1a..b44005e3 100644 --- a/src/PepperDash.Essentials.Core/Timers/CountdownTimer.cs +++ b/src/PepperDash.Essentials.Core/Timers/CountdownTimer.cs @@ -7,192 +7,152 @@ using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class SecondsCountdownTimer: IKeyed { + public event EventHandler HasStarted; + public event EventHandler HasFinished; + public event EventHandler WasCancelled; + + public string Key { get; private set; } + + public BoolFeedback IsRunningFeedback { get; private set; } + bool _isRunning; + + public IntFeedback PercentFeedback { get; private set; } + public StringFeedback TimeRemainingFeedback { get; private set; } + + public IntFeedback SecondsRemainingFeedback { get; private set; } + + public bool CountsDown { get; set; } + /// - /// Represents a SecondsCountdownTimer + /// The number of seconds to countdown /// - public class SecondsCountdownTimer: IKeyed + public int SecondsToCount { get; set; } + + public DateTime StartTime { get; private set; } + public DateTime FinishTime { get; private set; } + + private CTimer _secondTimer; + + /// + /// Constructor + /// + /// + public SecondsCountdownTimer(string key) { - /// - /// Event fired when the timer starts - /// - public event EventHandler HasStarted; + Key = key; + IsRunningFeedback = new BoolFeedback(() => _isRunning); - /// - /// Event fired when the timer finishes - /// - public event EventHandler HasFinished; + TimeRemainingFeedback = new StringFeedback(() => + { + // Need to handle up and down here. - /// - /// Event fired when the timer is cancelled - /// - public event EventHandler WasCancelled; + var timeSpan = FinishTime - DateTime.Now; - /// - /// Gets or sets the Key - /// - public string Key { get; private set; } + Debug.LogMessage(LogEventLevel.Verbose, + "timeSpan.Minutes == {0}, timeSpan.Seconds == {1}, timeSpan.TotalSeconds == {2}", this, + timeSpan.Minutes, timeSpan.Seconds, timeSpan.TotalSeconds); - /// - /// 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(() => + if (Math.Floor(timeSpan.TotalSeconds) < 60 && Math.Floor(timeSpan.TotalSeconds) >= 0) //ignore milliseconds { - // Need to handle up and down here. + return String.Format("{0:00}", timeSpan.Seconds); + } - var timeSpan = FinishTime - DateTime.Now; + return Math.Floor(timeSpan.TotalSeconds) < 0 + ? "00" + : String.Format("{0:00}:{1:00}", timeSpan.Minutes, timeSpan.Seconds); + }); - Debug.LogMessage(LogEventLevel.Verbose, - "timeSpan.Minutes == {0}, timeSpan.Seconds == {1}, timeSpan.TotalSeconds == {2}", this, - timeSpan.Minutes, timeSpan.Seconds, timeSpan.TotalSeconds); + SecondsRemainingFeedback = new IntFeedback(() => (int)(FinishTime - DateTime.Now).TotalSeconds); - if (Math.Floor(timeSpan.TotalSeconds) < 60 && Math.Floor(timeSpan.TotalSeconds) >= 0) //ignore milliseconds - { - return String.Format("{0:00}", timeSpan.Seconds); - } + PercentFeedback = + new IntFeedback( + () => + (int) + (Math.Floor((FinishTime - DateTime.Now).TotalSeconds)/ + Math.Floor((FinishTime - StartTime).TotalSeconds)*100)); + } - return Math.Floor(timeSpan.TotalSeconds) < 0 - ? "00" - : String.Format("{0:00}:{1:00}", timeSpan.Minutes, timeSpan.Seconds); - }); + /// + /// Starts the Timer + /// + public void Start() + { + if (_isRunning) + return; + StartTime = DateTime.Now; + FinishTime = StartTime + TimeSpan.FromSeconds(SecondsToCount); - SecondsRemainingFeedback = new IntFeedback(() => (int)(FinishTime - DateTime.Now).TotalSeconds); + if (_secondTimer != null) + _secondTimer.Stop(); + _secondTimer = new CTimer(SecondElapsedTimerCallback, null, 0, 1000); + _isRunning = true; + IsRunningFeedback.FireUpdate(); - PercentFeedback = - new IntFeedback( - () => - (int) - (Math.Floor((FinishTime - DateTime.Now).TotalSeconds)/ - Math.Floor((FinishTime - StartTime).TotalSeconds)*100)); - } + var handler = HasStarted; + if (handler != null) + handler(this, new EventArgs()); + } - /// - /// Start method - /// - public void Start() + /// + /// Restarts the timer + /// + public void Reset() + { + _isRunning = false; + IsRunningFeedback.FireUpdate(); + Start(); + } + + /// + /// Cancels the timer (without triggering it to finish) + /// + public void Cancel() + { + StopHelper(); + + var handler = WasCancelled; + if (handler != null) + handler(this, new EventArgs()); + } + + /// + /// Called upon expiration, or calling this will force timer to finish. + /// + public void Finish() + { + StopHelper(); + + var handler = HasFinished; + if (handler != null) + handler(this, new EventArgs()); + } + + void StopHelper() + { + if (_secondTimer != null) { - 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()); + _secondTimer.Stop(); + _secondTimer = null; } - /// - /// Reset method - /// - public void Reset() + _isRunning = false; + IsRunningFeedback.FireUpdate(); + } + + void SecondElapsedTimerCallback(object o) + { + if (DateTime.Now >= FinishTime) { - _isRunning = false; - IsRunningFeedback.FireUpdate(); - Start(); + Finish(); + return; } - /// - /// 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(); - } + PercentFeedback.FireUpdate(); + TimeRemainingFeedback.FireUpdate(); + SecondsRemainingFeedback.FireUpdate(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Timers/RetriggerableTimer.cs b/src/PepperDash.Essentials.Core/Timers/RetriggerableTimer.cs index f06ba3cd..14eb3d22 100644 --- a/src/PepperDash.Essentials.Core/Timers/RetriggerableTimer.cs +++ b/src/PepperDash.Essentials.Core/Timers/RetriggerableTimer.cs @@ -1,222 +1,170 @@ - - -using System; +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 +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 { - /// - /// 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; + + public RetriggerableTimer(string key, DeviceConfig config) + : base(key, config.Name) { - private RetriggerableTimerPropertiesConfig _propertiesConfig; + var props = config.Properties.ToObject(); + _propertiesConfig = props; - 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) + if (_propertiesConfig != null) { - var props = config.Properties.ToObject(); - _propertiesConfig = props; + _timerIntervalMs = _propertiesConfig.TimerIntervalMs; + } + } - if (_propertiesConfig != null) - { - _timerIntervalMs = _propertiesConfig.TimerIntervalMs; - } + public override bool CustomActivate() + { + if (_propertiesConfig.StartTimerOnActivation) + { + StartTimer(); } - /// - /// CustomActivate method - /// - /// - public override bool CustomActivate() + return base.CustomActivate(); + } + + private void CleanUpTimer() + { + if (_timer != null) { - 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)); + _timer.Dispose(); } - private DeviceActionWrapper GetActionFromConfig(eRetriggerableTimerEvents eventType) - { - var action = _propertiesConfig.Events[eRetriggerableTimerEvents.Elapsed]; + _timer = null; + } - if (action != null) - return action; - else return null; - } + public void StartTimer() + { + CleanUpTimer(); + Debug.LogMessage(LogEventLevel.Information, this, "Starting Timer"); - /// - /// 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"); + _timer = new CTimer(TimerElapsedCallback, GetActionFromConfig(eRetriggerableTimerEvents.Elapsed), _timerIntervalMs, _timerIntervalMs); + } - if (action == null) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Timer elapsed but unable to execute action. Action is null."); - return; - } + public void StopTimer() + { + Debug.LogMessage(LogEventLevel.Information, this, "Stopping Timer"); + _timer.Stop(); - var devAction = action as DeviceActionWrapper; - if (devAction != null) - ExecuteAction(devAction); - else - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to cast action as DeviceActionWrapper. Cannot Execute"); - } + ExecuteAction(GetActionFromConfig(eRetriggerableTimerEvents.Stopped)); + } - } + private DeviceActionWrapper GetActionFromConfig(eRetriggerableTimerEvents eventType) + { + var action = _propertiesConfig.Events[eRetriggerableTimerEvents.Elapsed]; - 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); - //} - } + if (action != null) + return action; + else return null; } /// - /// Configuration Properties for RetriggerableTimer + /// Executes the Elapsed action from confing when the timer elapses /// - public class RetriggerableTimerPropertiesConfig + /// + private void TimerElapsedCallback(object action) { - /// - /// Start the timer on device activation - /// - [JsonProperty("startTimerOnActivation")] - public bool StartTimerOnActivation { get; set; } + Debug.LogMessage(LogEventLevel.Debug, this, "Timer Elapsed. Executing Action"); - /// - /// 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() + if (action == null) { - 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" }; + Debug.LogMessage(LogEventLevel.Debug, this, "Timer elapsed but unable to execute action. Action is null."); + return; } - /// - /// BuildDevice method - /// - /// device config - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) + var devAction = action as DeviceActionWrapper; + if (devAction != null) + ExecuteAction(devAction); + else { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new RetriggerableTimer Device"); - - return new RetriggerableTimer(dc.Key, dc); + 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 +{ + [JsonProperty("startTimerOnActivation")] + public bool StartTimerOnActivation { get; set; } + + [JsonProperty("timerIntervalMs")] + public long TimerIntervalMs { get; set; } + + [JsonProperty("events")] + public Dictionary Events { get; set; } + + public RetriggerableTimerPropertiesConfig() + { + Events = new Dictionary(); + } +} + +/// +/// The set of values describing events on the timer +/// +public enum eRetriggerableTimerEvents +{ + Elapsed, + Stopped, +} + +/// +/// Factory class +/// +public class RetriggerableTimerFactory : EssentialsDeviceFactory +{ + public RetriggerableTimerFactory() + { + TypeNames = new List() { "retriggerabletimer" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new RetriggerableTimer Device"); + + return new RetriggerableTimer(dc.Key, dc); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs index 2cc9ab9a..478869b3 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs @@ -1,149 +1,90 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class CrestronTouchpanelPropertiesConfig { - /// - /// Represents a CrestronTouchpanelPropertiesConfig - /// - public class CrestronTouchpanelPropertiesConfig - { - /// - /// Gets or sets the ControlProperties - /// - [JsonProperty("control")] - public EssentialsControlPropertiesConfig ControlProperties { get; set; } + [JsonProperty("control")] + public EssentialsControlPropertiesConfig ControlProperties { get; set; } - /// - /// Gets or sets the IpId - /// - [JsonProperty("ipId", NullValueHandling = NullValueHandling.Ignore)] - public string IpId { get; set; } + [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; } + [JsonProperty("defaultRoomKey", NullValueHandling = NullValueHandling.Ignore)] + public string DefaultRoomKey { get; set; } + + [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; } + [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; } + [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; } + [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; } + [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; } + [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; } + [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; } + [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; } + [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; } + [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; } + [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; } + [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 + /// The count of sources that will trigger the "additional" arrows to show on the SRL. + /// Defaults to 5 /// - public class UiSetupPropertiesConfig + [JsonProperty("sourcesOverflowCount", NullValueHandling = NullValueHandling.Ignore)] + public int? SourcesOverflowCount { get; set; } + + public CrestronTouchpanelPropertiesConfig() : this(false) { } + + public CrestronTouchpanelPropertiesConfig(bool setDefaultValues = false) { - /// - /// Gets or sets the IsVisible - /// - [JsonProperty("isVisible", NullValueHandling = NullValueHandling.Ignore)] - public bool IsVisible { get; set; } - } + 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"; +} + +/// +/// +/// +public class UiSetupPropertiesConfig +{ + [JsonProperty("isVisible", NullValueHandling = NullValueHandling.Ignore)] + public bool IsVisible { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Touchpanels/Interfaces.cs b/src/PepperDash.Essentials.Core/Touchpanels/Interfaces.cs index 0e74ed93..0d18f133 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/Interfaces.cs @@ -1,20 +1,15 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +/// +/// Defines the contract for IHasBasicTriListWithSmartObject +/// +public interface IHasBasicTriListWithSmartObject { /// - /// Defines the contract for IHasBasicTriListWithSmartObject + /// Gets the Panel /// - public interface IHasBasicTriListWithSmartObject - { - /// - /// Gets the Panel - /// - BasicTriListWithSmartObject Panel { get; } - } -} \ No newline at end of file + BasicTriListWithSmartObject Panel { get; } +} diff --git a/src/PepperDash.Essentials.Core/Touchpanels/Keyboards/HabaneroKeyboardController.cs b/src/PepperDash.Essentials.Core/Touchpanels/Keyboards/HabaneroKeyboardController.cs index 89346ae7..ea3dd372 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/Keyboards/HabaneroKeyboardController.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/Keyboards/HabaneroKeyboardController.cs @@ -1,247 +1,209 @@ 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 +namespace PepperDash.Essentials.Core.Touchpanels.Keyboards; + +public class HabaneroKeyboardController { /// - /// Represents a HabaneroKeyboardController + /// Single-key press events, rather than using a built-up text string on the OutputFeedback /// - public class HabaneroKeyboardController - { - /// - /// Single-key press events, rather than using a built-up text string on the OutputFeedback - /// - public event EventHandler KeyPress; + public event EventHandler KeyPress; - /// - /// Gets or sets the TriList - /// - public BasicTriList TriList { get; private set; } + public BasicTriList TriList { get; private set; } - /// - /// Gets or sets the OutputFeedback - /// - public StringFeedback OutputFeedback { get; private set; } + public StringFeedback OutputFeedback { get; private set; } - /// - /// Gets or sets the IsVisible - /// - public bool IsVisible { get; private set; } + public bool IsVisible { get; private set; } - /// - /// Gets or sets the DotComButtonString - /// - public string DotComButtonString { get; set; } + public string DotComButtonString { get; set; } - /// - /// Gets or sets the GoButtonText - /// - public string GoButtonText { get; set; } + public string GoButtonText { get; set; } - /// - /// Gets or sets the SecondaryButtonText - /// - public string SecondaryButtonText { get; set; } + public string SecondaryButtonText { get; set; } - /// - /// Gets or sets the GoButtonVisible - /// - public bool GoButtonVisible { get; set; } + public bool GoButtonVisible { get; set; } - /// - /// Gets or sets the SecondaryButtonVisible - /// - public bool SecondaryButtonVisible { get; set; } + public bool SecondaryButtonVisible { get; set; } - int ShiftMode = 0; - - StringBuilder Output; + int ShiftMode = 0; + + StringBuilder Output; - /// - /// Gets or sets the HideAction - /// - public Action HideAction { get; set; } + public Action HideAction { get; set; } CTimer BackspaceTimer; - /// - /// - /// - /// - public HabaneroKeyboardController(BasicTriList trilist) - { - TriList = trilist; - Output = new StringBuilder(); - OutputFeedback = new StringFeedback(() => Output.ToString()); - DotComButtonString = ".com"; - } + /// + /// + /// + /// + public HabaneroKeyboardController(BasicTriList trilist) + { + TriList = trilist; + Output = new StringBuilder(); + OutputFeedback = new StringFeedback(() => Output.ToString()); + DotComButtonString = ".com"; + } - /// - /// Show method - /// - public void Show() - { - if (IsVisible) - return; + /// + /// Shows the keyboard and attaches sig handlers in the range of 2901-2969 + /// + 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.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.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(GoButtonVisibleJoin, GoButtonVisible); + TriList.SetString(GoButtonTextJoin, GoButtonText); + TriList.SetBool(SecondaryButtonVisibleJoin, SecondaryButtonVisible); + TriList.SetString(SecondaryButtonTextJoin, SecondaryButtonText); - TriList.SetBool(KeyboardVisible, true); + TriList.SetBool(KeyboardVisible, true); + ShowKeys(); + IsVisible = true; + } + + /// + /// Hides the keyboard and disconnects ALL sig handlers from 2901 - 2969 + /// + 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; + } + + /// + /// + /// + /// + public void Press(char c) + { + OnKeyPress(c.ToString()); + Output.Append(c); + OutputFeedback.FireUpdate(); + ResetShift(); + } + + /// + /// + /// + /// + public void Press(string s) + { + OnKeyPress(s); + Output.Append(s); + OutputFeedback.FireUpdate(); + ResetShift(); + } + + /// + /// + /// + public void EnableGoButton() + { + TriList.SetBool(GoButtonEnableJoin, true); + } + + /// + /// + /// + public void DisableGoButton() + { + TriList.SetBool(GoButtonEnableJoin, false); + } + + void ResetShift() + { + if (ShiftMode == 1) + { + ShiftMode = 0; ShowKeys(); - IsVisible = true; } - - /// - /// Hide method - /// - public void Hide() + else if (ShiftMode == 3) { - 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; + ShiftMode = 2; + ShowKeys(); } + } - /// - /// - /// - /// - /// - /// 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]; } + 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 @@ -266,248 +228,206 @@ namespace PepperDash.Essentials.Core.Touchpanels.Keyboards } } - void Backspace() + void Backspace() + { + OnKeyPress(KeyboardSpecialKey.Backspace); + + if (Output.Length > 0) { - 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); + Output.Remove(Output.Length - 1, 1); 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; + void Clear() + { + OnKeyPress(KeyboardSpecialKey.Clear); - ShowKeys(); - } + Output.Remove(0, Output.Length); + OutputFeedback.FireUpdate(); + } - void NumShift() - { - if (ShiftMode == 0 || ShiftMode == 1) - ShiftMode = 2; - else if (ShiftMode == 2 || ShiftMode == 3) - ShiftMode = 0; - ShowKeys(); - } + /* 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; - 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); + ShowKeys(); + } - TriList.SetUshort(2951, (ushort)ShiftMode); // 0 = up, 1 = down, 2 = #, 3 = 123 - TriList.SetUshort(2952, (ushort)(ShiftMode < 2 ? 0 : 1)); // 0 = #, 1 = abc - } + void NumShift() + { + if (ShiftMode == 0 || ShiftMode == 1) + ShiftMode = 2; + else if (ShiftMode == 2 || ShiftMode == 3) + ShiftMode = 0; + ShowKeys(); + } - /// - /// 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; + 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 args for keyboard key presses + /// Event fire helper for text /// - public class KeyboardControllerPressEventArgs : EventArgs + /// + void OnKeyPress(string text) { - /// - /// 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; - } + var handler = KeyPress; + if (handler != null) + KeyPress(this, new KeyboardControllerPressEventArgs(text)); } /// - /// Enumeration of KeyboardSpecialKey values + /// event helper for special keys /// - public enum KeyboardSpecialKey + /// + void OnKeyPress(KeyboardSpecialKey key) { - /// - /// None - /// - None = 0, - - /// - /// Backspace - /// - Backspace, - - /// - /// Clear - /// - Clear, - - /// - /// GoButton - /// - GoButton, - - /// - /// SecondaryButton - /// - SecondaryButton + 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; + +} + +/// +/// +/// +public class KeyboardControllerPressEventArgs : EventArgs +{ + public string Text { get; private set; } + public KeyboardSpecialKey SpecialKey { get; private set; } + + public KeyboardControllerPressEventArgs(string text) + { + Text = text; + } + + public KeyboardControllerPressEventArgs(KeyboardSpecialKey key) + { + SpecialKey = key; + } +} + +public enum KeyboardSpecialKey +{ + None = 0, Backspace, Clear, GoButton, SecondaryButton } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs b/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs index e3545cd0..f3bd2e89 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs @@ -1,14 +1,10 @@ using System; -using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ - /// - /// Represents a ModalDialog - /// +namespace PepperDash.Essentials.Core; + public class ModalDialog { /// @@ -19,10 +15,10 @@ namespace PepperDash.Essentials.Core /// Bool press 3992 /// public const uint Button2Join = 3992; - /// - /// 3993 - /// - public const uint CancelButtonJoin = 3993; + /// + /// 3993 + /// + public const uint CancelButtonJoin = 3993; /// ///For visibility of single button. Bool feedback 3994 /// @@ -35,19 +31,19 @@ namespace PepperDash.Essentials.Core /// 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; + /// + /// 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 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 /// @@ -82,10 +78,10 @@ namespace PepperDash.Essentials.Core get { return TriList.BooleanInput[ModalVisibleJoin].BoolValue; } } - /// - /// - /// - public bool CanCancel { get; private set; } + /// + /// + /// + public bool CanCancel { get; private set; } BasicTriList TriList; @@ -103,10 +99,10 @@ namespace PepperDash.Essentials.Core TriList = triList; // Attach actions to buttons - triList.SetSigFalseAction(Button1Join, () => OnModalComplete(1)); + triList.SetSigFalseAction(Button1Join, () => OnModalComplete(1)); triList.SetSigFalseAction(Button2Join, () => OnModalComplete(2)); - triList.SetSigFalseAction(CancelButtonJoin, () => { if (CanCancel) CancelDialog(); }); - CanCancel = true; + triList.SetSigFalseAction(CancelButtonJoin, () => { if (CanCancel) CancelDialog(); }); + CanCancel = true; } /// @@ -156,15 +152,15 @@ namespace PepperDash.Essentials.Core TriList.StringInput[Button2TextJoin].StringValue = button2Text; } // Show/hide guage - TriList.BooleanInput[TimerVisibleJoin].BoolValue = showGauge; - - CanCancel = showCancel; - TriList.BooleanInput[CancelVisibleJoin].BoolValue = showCancel; + TriList.BooleanInput[TimerVisibleJoin].BoolValue = showGauge; + + CanCancel = showCancel; + TriList.BooleanInput[CancelVisibleJoin].BoolValue = showCancel; //Reveal and activate TriList.BooleanInput[ModalVisibleJoin].BoolValue = true; - WakePanel(); + WakePanel(); return true; } @@ -172,49 +168,47 @@ namespace PepperDash.Essentials.Core return false; } - /// - /// WakePanel method - /// - public void WakePanel() - { - try - { - var panel = TriList as TswFt5Button; + /// + /// Wakes the panel by turning on the backlight if off + /// + 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?"); - } - } + if (panel != null && panel.ExtenderSystemReservedSigs.BacklightOffFeedback.BoolValue) + panel.ExtenderSystemReservedSigs.BacklightOn(); + } + catch + { + Debug.LogMessage(LogEventLevel.Debug, "Error Waking Panel. Maybe testing with Xpanel?"); + } + } - /// - /// CancelDialog method - /// + /// + /// Hide dialog from elsewhere, fires CompleteAction + /// public void CancelDialog() { - OnModalComplete(0); + OnModalComplete(0); } - /// - /// Hides dialog. Fires no action - /// - public void HideDialog() - { - TriList.BooleanInput[ModalVisibleJoin].BoolValue = false; - } + /// + /// 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); + var action = ModalCompleteAction; + if (action != null) + action(buttonNum); } - } - -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Touchpanels/Mpc3Touchpanel.cs b/src/PepperDash.Essentials.Core/Touchpanels/Mpc3Touchpanel.cs index 92764f22..2fb8cb59 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/Mpc3Touchpanel.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/Mpc3Touchpanel.cs @@ -7,8 +7,8 @@ using PepperDash.Core; using PepperDash.Core.Logging; using Serilog.Events; -namespace PepperDash.Essentials.Core.Touchpanels -{ +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 @@ -85,9 +85,9 @@ namespace PepperDash.Essentials.Core.Touchpanels return; } - TryParseInt(key, out int buttonNumber); + TryParseInt(key, out int buttonNumber); - var buttonEventTypes = config.EventTypes; + var buttonEventTypes = config.EventTypes; BoolOutputSig enabledFb = null; BoolOutputSig disabledFb = null; @@ -174,10 +174,10 @@ namespace PepperDash.Essentials.Core.Touchpanels return; } - TryParseInt(key, out int buttonNumber); + TryParseInt(key, out int buttonNumber); - // Link up the button feedbacks to the specified device feedback - var buttonFeedback = config.Feedback; + // 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.", @@ -189,14 +189,14 @@ namespace PepperDash.Essentials.Core.Touchpanels 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; - } + 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); + deviceFeedback = device.GetFeedbackProperty(buttonFeedback.FeedbackName); if (deviceFeedback == null) { Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedbackName property '{1}' not found.", @@ -236,36 +236,36 @@ namespace PepperDash.Essentials.Core.Touchpanels var boolFeedback = deviceFeedback as BoolFeedback; - switch (key) - { - case ("power"): + switch (key) + { + case ("power"): + { + boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackPower); + break; + } + case ("volumeup"): + case ("volumedown"): + case ("volumefeedback"): + { + if (deviceFeedback is IntFeedback intFeedback) { - boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackPower); - break; + var volumeFeedback = intFeedback; + volumeFeedback.LinkInputSig(_touchpanel.VolumeBargraph); } - 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; - } - } + break; + } + case ("mute"): + { + boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackMute); + break; + } + default: + { + boolFeedback?.LinkCrestronFeedback(_touchpanel.Feedbacks[(uint)buttonNumber]); + break; + } } + } /// /// Try parse int helper method @@ -393,5 +393,4 @@ namespace PepperDash.Essentials.Core.Touchpanels /// [JsonProperty("feedbackName")] public string FeedbackName { get; set; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Touchpanels/TriListExtensions.cs b/src/PepperDash.Essentials.Core/Touchpanels/TriListExtensions.cs index 2d026dbb..a9713be2 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/TriListExtensions.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/TriListExtensions.cs @@ -1,16 +1,11 @@ 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 -{ +namespace PepperDash.Essentials.Core; + /// /// Extensions used for more-clear attachment of Actions to user objects on sigs /// @@ -18,7 +13,7 @@ namespace PepperDash.Essentials.Core { /// /// Attaches Action to Sig's user object and returns the same Sig. This provides no protection - /// from null sigs + /// from null sigs /// /// The BoolOutputSig to attach the Action to /// An action to run when sig is pressed and when released @@ -74,14 +69,14 @@ namespace PepperDash.Essentials.Core 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 + /// + /// 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 @@ -124,17 +119,14 @@ namespace PepperDash.Essentials.Core } - /// - /// 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) - { + /// + /// Sets an action to a held sig as well as a released-without-hold action + /// + /// The sig + 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 @@ -232,35 +224,35 @@ namespace PepperDash.Essentials.Core return ClearSigAction(tl.StringOutput[sigNum]) as StringOutputSig; } - /// - /// ClearAllSigActions method - /// - public static void ClearAllSigActions(this BasicTriList t1) + /// + /// Clears all actions on all sigs + /// + public static void ClearAllSigActions(this BasicTriList t1) + { + foreach (var sig in t1.BooleanOutput) { - foreach (var sig in t1.BooleanOutput) - { - ClearSigAction(sig); - } - - foreach (var sig in t1.UShortOutput) - { - ClearSigAction(sig); - } - - foreach (var sig in t1.StringOutput) - { - ClearSigAction(sig); - } + ClearSigAction(sig); } - /// - /// SetBool method - /// - public static void SetBool(this BasicTriList tl, uint sigNum, bool value) + foreach (var sig in t1.UShortOutput) { - tl.BooleanInput[sigNum].BoolValue = value; + ClearSigAction(sig); } + foreach (var sig in t1.StringOutput) + { + ClearSigAction(sig); + } + } + + /// + /// Helper method to set the value of a bool Sig on TriList + /// + public static void SetBool(this BasicTriList tl, uint sigNum, bool value) + { + tl.BooleanInput[sigNum].BoolValue = value; + } + /// /// Sends an true-false pulse to the sig /// @@ -282,21 +274,21 @@ namespace PepperDash.Essentials.Core 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 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 + /// + 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 @@ -343,5 +335,4 @@ namespace PepperDash.Essentials.Core { return tl.StringOutput[sigNum].StringValue; } - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/TriListBridges/HandlerBridge.cs b/src/PepperDash.Essentials.Core/TriListBridges/HandlerBridge.cs index 13676e2d..bd90ede7 100644 --- a/src/PepperDash.Essentials.Core/TriListBridges/HandlerBridge.cs +++ b/src/PepperDash.Essentials.Core/TriListBridges/HandlerBridge.cs @@ -1,32 +1,22 @@ -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 + +namespace PepperDash.Essentials.Core; +/// +/// Abstract base class for TriList handler bridges +/// +public abstract class HandlerBridge { /// - /// Abstract base class for TriList handler bridges + /// Gets or sets the IsAttached /// - public abstract class HandlerBridge - { - /// - /// Gets or sets the IsAttached - /// - public bool IsAttached { get; protected set; } + public bool IsAttached { get; protected set; } - /// - /// Attaches the handler to the panel's user objects - /// - public abstract void AttachToTriListOutputs(bool sendUpdate); + /// + /// 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(); - } + /// + /// Removes the handler from the panel's user objects + /// + public abstract void DetachFromTriListOutputs(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/UI PageManagers/BlurayPageManager.cs b/src/PepperDash.Essentials.Core/UI PageManagers/BlurayPageManager.cs index d14058bd..d5c54a31 100644 --- a/src/PepperDash.Essentials.Core/UI PageManagers/BlurayPageManager.cs +++ b/src/PepperDash.Essentials.Core/UI PageManagers/BlurayPageManager.cs @@ -1,11 +1,7 @@ using Crestron.SimplSharpPro.DeviceSupport; -using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.PageManagers -{ - /// - /// Represents a DiscPlayerMediumPageManager - /// +namespace PepperDash.Essentials.Core.PageManagers; + public class DiscPlayerMediumPageManager : MediumLeftSwitchablePageManager { IDiscPlayerControls Player; @@ -54,5 +50,4 @@ namespace PepperDash.Essentials.Core.PageManagers TriList.BooleanInput[BackingPageJoin].BoolValue = false; TriList.BooleanInput[LeftSubpageJoin].BoolValue = false; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/UI PageManagers/PageManager.cs b/src/PepperDash.Essentials.Core/UI PageManagers/PageManager.cs index ed5f0fff..79d23f19 100644 --- a/src/PepperDash.Essentials.Core/UI PageManagers/PageManager.cs +++ b/src/PepperDash.Essentials.Core/UI PageManagers/PageManager.cs @@ -2,8 +2,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.PageManagers -{ +namespace PepperDash.Essentials.Core.PageManagers; + /// /// The PageManager classes are used to bridge a device to subpage /// visibility. @@ -152,5 +152,4 @@ namespace PepperDash.Essentials.Core.PageManagers { return GetOffsetJoin(DisplayUiType); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxThreePanelPageManager.cs b/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxThreePanelPageManager.cs index 338f47dc..ddf598a2 100644 --- a/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxThreePanelPageManager.cs +++ b/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxThreePanelPageManager.cs @@ -3,226 +3,221 @@ 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 +namespace PepperDash.Essentials.Core.PageManagers; + +public class ThreePanelPlusOnePageManager : PageManager { /// - /// Represents a ThreePanelPlusOnePageManager + /// The trilist /// - 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; - } - } - - + protected BasicTriListWithSmartObject TriList; /// - /// Represents a SetTopBoxThreePanelPageManager + /// Gets or sets the Position5TabsId /// - public class SetTopBoxThreePanelPageManager : ThreePanelPlusOnePageManager + 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) { - ISetTopBoxControls SetTopBox; - DevicePresetsView PresetsView; + TriList = trilist; + CurrentVisiblePosition5Item = 1; + } - /// - /// 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) + /// + /// The joins for the switchable panel in position 5 + /// + Dictionary Position5SubpageJoins = new Dictionary { - PresetsView = new DevicePresetsView(trilist, stb.TvPresets); - } - } + { 1, 10053 }, + { 2, 10054 } + }; - /// - /// Show method - /// - /// - public override void Show() - { - if(PresetsView != null) - PresetsView.Attach(); - base.Show(); - } + /// + /// + /// + 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; - /// - /// Hide method - /// - /// - public override void Hide() + if (ShowPosition5Tabs) { - if (PresetsView != null) - PresetsView.Detach(); - base.Hide(); + // 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(); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxTwoPanelPageManager.cs b/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxTwoPanelPageManager.cs index 0e5b520a..83482e88 100644 --- a/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxTwoPanelPageManager.cs +++ b/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxTwoPanelPageManager.cs @@ -2,8 +2,8 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Presets; -namespace PepperDash.Essentials.Core.PageManagers -{ +namespace PepperDash.Essentials.Core.PageManagers; + /// /// Represents a SetTopBoxMediumPageManager /// @@ -68,5 +68,4 @@ namespace PepperDash.Essentials.Core.PageManagers TriList.BooleanInput[BackingPageJoin].BoolValue = false; TriList.BooleanInput[LeftSubpageJoin].BoolValue = false; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/UI PageManagers/SinglePageManager.cs b/src/PepperDash.Essentials.Core/UI PageManagers/SinglePageManager.cs index 3eb0cf80..9afa0555 100644 --- a/src/PepperDash.Essentials.Core/UI PageManagers/SinglePageManager.cs +++ b/src/PepperDash.Essentials.Core/UI PageManagers/SinglePageManager.cs @@ -2,8 +2,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.PageManagers -{ +namespace PepperDash.Essentials.Core.PageManagers; + /// /// Represents a SinglePageManager /// @@ -39,5 +39,4 @@ namespace PepperDash.Essentials.Core.PageManagers { TriList.BooleanInput[BackingPageJoin].BoolValue = false; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/UI/TouchpanelBase.cs b/src/PepperDash.Essentials.Core/UI/TouchpanelBase.cs index fd9da802..83601cc4 100644 --- a/src/PepperDash.Essentials.Core/UI/TouchpanelBase.cs +++ b/src/PepperDash.Essentials.Core/UI/TouchpanelBase.cs @@ -4,177 +4,167 @@ 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 +namespace PepperDash.Essentials.Core.UI; + +public abstract class TouchpanelBase : EssentialsDevice, IHasBasicTriListWithSmartObject { + protected CrestronTouchpanelPropertiesConfig _config; + public BasicTriListWithSmartObject Panel { get; private set; } + /// - /// Base class for Touchpanel devices + /// 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. /// - public abstract class TouchpanelBase : EssentialsDevice, IHasBasicTriListWithSmartObject + /// Essentials Device Key + /// Essentials Device Name + /// Touchpanel Type to build + /// Touchpanel Configuration + /// IP-ID to use for touch panel + protected TouchpanelBase(string key, string name, BasicTriListWithSmartObject panel, CrestronTouchpanelPropertiesConfig config) + : base(key, name) { - /// - /// 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; + } - if (panel == null) + 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(() => + { + if (Panel.Register() != eDeviceRegistrationUnRegistrationResponse.Success) + Debug.LogMessage(LogEventLevel.Information, this, "WARNING: Registration failed. Continuing, but panel may not function: {0}", Panel.RegistrationFailureReason); + + // Give up cleanly if SGD is not present. + var sgdName = Global.FilePathPrefix + "sgd" + Global.DirectorySeparator + _config.SgdFile; + if (!File.Exists(sgdName)) { - Debug.LogMessage(LogEventLevel.Information, this, "Panel is not valid. Touchpanel class WILL NOT work correctly"); - return; - } + Debug.LogMessage(LogEventLevel.Information, this, "Smart object file '{0}' not present in User folder. Looking for embedded file", sgdName); - Panel = panel; + sgdName = Global.ApplicationDirectoryPathPrefix + Global.DirectorySeparator + "SGD" + Global.DirectorySeparator + _config.SgdFile; - 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; - } + Debug.LogMessage(LogEventLevel.Information, this, "Unable to find SGD file '{0}' in User sgd or application SGD folder. Exiting touchpanel load.", sgdName); + return; } + } - Panel.LoadSmartObjects(sgdName); - }); + Panel.LoadSmartObjects(sgdName); + }); - AddPostActivationAction(() => + AddPostActivationAction(() => + { + // Check for IEssentialsRoomCombiner in DeviceManager and if found, subscribe to its event + var roomCombiner = DeviceManager.AllDevices.FirstOrDefault((d) => d is IEssentialsRoomCombiner) as IEssentialsRoomCombiner; + + if (roomCombiner != null) { - // Check for IEssentialsRoomCombiner in DeviceManager and if found, subscribe to its event + // Subscribe to the even + roomCombiner.RoomCombinationScenarioChanged += new EventHandler(roomCombiner_RoomCombinationScenarioChanged); - if (DeviceManager.AllDevices.FirstOrDefault((d) => d is IEssentialsRoomCombiner) is IEssentialsRoomCombiner roomCombiner) + // Connect to the initial roomKey + if (roomCombiner.CurrentScenario != null) { - // 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); - } + // Use the current scenario + DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario); } else { - // No room combiner, use the default key + // Current Scenario not yet set. Use default 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)) + else { - newRoomKey = scenario.UiMap[_config.DefaultRoomKey]; + // No room combiner, use the default key + SetupPanelDrivers(_config.DefaultRoomKey); } + }); + } - SetupPanelDrivers(newRoomKey); - } + /// + /// Setup Panel operation + /// + /// Room Key for this panel + protected abstract void SetupPanelDrivers(string roomKey); - private void Panel_SigChange(object currentDevice, SigEventArgs args) + + /// + /// 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)) { - 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); + newRoomKey = scenario.UiMap[Key]; + } + else if (scenario.UiMap.ContainsKey(_config.DefaultRoomKey)) + { + newRoomKey = scenario.UiMap[_config.DefaultRoomKey]; } - 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); - } + SetupPanelDrivers(newRoomKey); + } + + private void Panel_SigChange(object currentDevice, Crestron.SimplSharpPro.SigEventArgs args) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "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); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Utilities/ActionSequence.cs b/src/PepperDash.Essentials.Core/Utilities/ActionSequence.cs index 22c9297c..aaea7b66 100644 --- a/src/PepperDash.Essentials.Core/Utilities/ActionSequence.cs +++ b/src/PepperDash.Essentials.Core/Utilities/ActionSequence.cs @@ -2,186 +2,156 @@ 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 +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 { - /// - /// 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; + + public ActionSequence(string key, DeviceConfig config) + : base(key, config.Name) { - private ActionSequencePropertiesConfig _propertiesConfig; + var props = config.Properties.ToObject(); + _propertiesConfig = props; - private CrestronQueue _actionQueue; - - private Thread _worker; - - private bool _allowActionsToExecute; - - /// - /// Constructor - /// - /// - /// - public ActionSequence(string key, DeviceConfig config) - : base(key, config.Name) + if (_propertiesConfig != null) { - var props = config.Properties.ToObject(); - _propertiesConfig = props; - - if (_propertiesConfig != null) + if (_propertiesConfig.ActionSequence.Count > 0) { - if (_propertiesConfig.ActionSequence.Count > 0) - { - _actionQueue = new CrestronQueue(_propertiesConfig.ActionSequence.Count); - } + _actionQueue = new CrestronQueue(_propertiesConfig.ActionSequence.Count); } } + } - /// - /// StartSequence method - /// - public void StartSequence() + /// + /// Starts executing the sequenced actions + /// + public void StartSequence() + { + if (_worker !=null && _worker.ThreadState == Thread.eThreadStates.ThreadRunning) { - 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); + Debug.LogMessage(LogEventLevel.Debug, this, "Thread already running. Cannot Start Sequence"); + return; } - /// - /// StopSequence method - /// - public void StopSequence() + Debug.LogMessage(LogEventLevel.Debug, this, "Starting Action Sequence"); + _allowActionsToExecute = true; + AddActionsToQueue(); + _worker = new Thread(ProcessActions, null, Thread.eThreadStartOptions.Running); + } + + /// + /// Stops executing the sequenced actions + /// + 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++) { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Action Sequence"); - _allowActionsToExecute = false; - _worker.Abort(); + _actionQueue.Enqueue(_propertiesConfig.ActionSequence[i]); } + } - /// - /// Populates the queue from the configuration information - /// - private void AddActionsToQueue() + private object ProcessActions(object obj) + { + while (_allowActionsToExecute && _actionQueue.Count > 0) { - Debug.LogMessage(LogEventLevel.Debug, this, "Adding {0} actions to queue", _propertiesConfig.ActionSequence.Count); + SequencedDeviceActionWrapper action = null; - 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) - { + action = _actionQueue.Dequeue(); if (action == null) - return; + break; - try - { - DeviceJsonApi.DoDeviceAction(action); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Error Executing Action: {0}", e); - } + // Delay before executing + if (action.DelayMs > 0) + Thread.Sleep(action.DelayMs); + + ExecuteAction(action); } + + return null; } - /// - /// Represents a ActionSequencePropertiesConfig - /// - public class ActionSequencePropertiesConfig + private void ExecuteAction(DeviceActionWrapper action) { - /// - /// Gets or sets the ActionSequence - /// - [JsonProperty("actionSequence")] - public List ActionSequence { get; set; } + if (action == null) + return; - /// - /// Constructor - /// - public ActionSequencePropertiesConfig() + try { - ActionSequence = new List(); + DeviceJsonApi.DoDeviceAction(action); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Error Executing Action: {0}", e); } } +} - /// - /// Represents a SequencedDeviceActionWrapper - /// - public class SequencedDeviceActionWrapper : DeviceActionWrapper +/// +/// Configuration Properties for ActionSequence +/// +public class ActionSequencePropertiesConfig +{ + [JsonProperty("actionSequence")] + public List ActionSequence { get; set; } + + public ActionSequencePropertiesConfig() { - /// - /// Gets or sets the DelayMs - /// - [JsonProperty("delayMs")] - public int DelayMs { get; set; } + ActionSequence = new List(); } +} - /// - /// Represents a ActionSequenceFactory - /// - public class ActionSequenceFactory : EssentialsDeviceFactory +public class SequencedDeviceActionWrapper : DeviceActionWrapper +{ + [JsonProperty("delayMs")] + public int DelayMs { get; set; } +} + +/// +/// Factory class +/// +public class ActionSequenceFactory : EssentialsDeviceFactory +{ + public ActionSequenceFactory() { - /// - /// 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); - } + TypeNames = new List() { "actionsequence" }; } + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new ActionSequence Device"); + + return new ActionSequence(dc.Key, dc); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/VideoStatus/VideoStatusOutputs.cs b/src/PepperDash.Essentials.Core/VideoStatus/VideoStatusOutputs.cs index b5151f79..44fbf31d 100644 --- a/src/PepperDash.Essentials.Core/VideoStatus/VideoStatusOutputs.cs +++ b/src/PepperDash.Essentials.Core/VideoStatus/VideoStatusOutputs.cs @@ -6,8 +6,8 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DM; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Use this class to pass in values to RoutingInputPorts. Unused properties will have default /// funcs assigned to them. @@ -196,5 +196,4 @@ namespace PepperDash.Essentials.Core // bool VideoSync { get; } //} - //public delegate void VideoStatusChangeHandler(IBasicVideoStatus device, eVideoStatusChangeType type); -} \ No newline at end of file + //public delegate void VideoStatusChangeHandler(IBasicVideoStatus device, eVideoStatusChangeType type); \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs b/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs index ffbe5509..f73b3f2c 100644 --- a/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs +++ b/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs @@ -8,281 +8,278 @@ using PepperDash.Core.Web; using PepperDash.Essentials.Core.Web.RequestHandlers; using Serilog.Events; -namespace PepperDash.Essentials.Core.Web + +namespace PepperDash.Essentials.Core.Web; + +/// +/// Represents a EssentialsWebApi +/// +public class EssentialsWebApi : EssentialsDevice { - /// - /// Represents a EssentialsWebApi - /// - public class EssentialsWebApi : EssentialsDevice - { - private readonly WebApiServer _server; + private readonly WebApiServer _server; - /// - /// 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"; + /// + /// 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; + 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; } + /// + /// Gets or sets the BasePath + /// + public string BasePath { get; private set; } - /// - /// Tracks if CWS is registered - /// - public bool IsRegistered - { - get { return _server.IsRegistered; } - } + /// + /// 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) + : this(key, name, null) + { + } - /// - /// Constructor - /// - /// - /// - /// - public EssentialsWebApi(string key, string name, EssentialsWebApiPropertiesConfig config) - : base(key, name) - { - Key = key; + /// + /// 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; + if (config == null) + BasePath = _defaultBasePath; + else + BasePath = string.IsNullOrEmpty(config.BasePath) ? _defaultBasePath : config.BasePath; - _server = new WebApiServer(Key, Name, BasePath); + _server = new WebApiServer(Key, Name, BasePath); - SetupRoutes(); - } + SetupRoutes(); + } - private void SetupRoutes() - { - var routes = new List - { - 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() - }, - }; - - AddRoute(routes); - } - - /// - /// Add a single route to the API. MUST be done during the activation phase - /// - /// - /// - /// AddRoute method - /// - public void AddRoute(HttpCwsRoute route) + private void SetupRoutes() + { + var routes = new List { - _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) + new HttpCwsRoute("versions") { - AddRoute(route); - } + 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() + }, + }; + + AddRoute(routes); + } + + /// + /// Add a single route to the API. MUST be done during the activation phase + /// + /// + 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); + } + } + + /// + /// Initializes the CWS class + /// + 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(); + + GetPaths(); + + return; } - /// - /// Initialize method - /// - /// - public override void Initialize() - { - AddRoute(new HttpCwsRoute("apiPaths") { - Name = "GetPaths", - RouteHandler = new GetRoutesHandler(_server.GetRouteCollection(), BasePath) - }); + // Automatically start CWS when running on a server (Linux OS, Virtual Control) + Debug.LogMessage(LogEventLevel.Verbose, "Starting Essentials Web API on Virtual Control Server"); - // 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; + _server.Start(); - var is4Series = eCrestronSeries.Series4 == (Global.ProcessorSeries & eCrestronSeries.Series4); - Debug.LogMessage(LogEventLevel.Verbose, "Starting Essentials Web API on {0} Appliance", is4Series ? "4-series" : "3-series"); + GetPaths(); + } - _server.Start(); + /// + /// Print the available pahts + /// + /// + /// 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)); - GetPaths(); + var currentIp = CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); - return; - } + var hostname = CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); - // Automatically start CWS when running on a server (Linux OS, Virtual Control) - Debug.LogMessage(LogEventLevel.Verbose, "Starting Essentials Web API on Virtual Control Server"); + var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server + ? $"https://{hostname}/VirtualControl/Rooms/{InitialParametersClass.RoomId}/cws{BasePath}" + : $"https://{currentIp}/cws{BasePath}"; - _server.Start(); + Debug.LogMessage(LogEventLevel.Information, this, "Server:{path:l}", path); - GetPaths(); - } - - /// - /// Print the available pahts - /// - /// - /// 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.LogMessage(LogEventLevel.Information, this, new string('-', 50)); - } - } + 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.LogMessage(LogEventLevel.Information, this, new string('-', 50)); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiFactory.cs b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiFactory.cs index 16abd349..4a8f25e0 100644 --- a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiFactory.cs +++ b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiFactory.cs @@ -3,34 +3,33 @@ using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core.Web +namespace PepperDash.Essentials.Core.Web; + +/// +/// Factory for creating EssentialsWebApi devices +/// +public class EssentialsWebApiFactory : EssentialsDeviceFactory { - /// - /// Represents a EssentialsWebApiFactory - /// - public class EssentialsWebApiFactory : EssentialsDeviceFactory + /// + /// Constructor + /// + public EssentialsWebApiFactory() { - /// - /// Constructor - /// - public EssentialsWebApiFactory() - { - TypeNames = new List { "EssentialsWebApi" }; - } + 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"); + /// + /// 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); + 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; - } + Debug.LogMessage(LogEventLevel.Debug, "Factory failed to create new Essentials Web API Server"); + return null; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs index 75f90189..243667c0 100644 --- a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs +++ b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs @@ -1,114 +1,112 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp.WebScripting; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Web +namespace PepperDash.Essentials.Core.Web; + +/// +/// EssentialsWebApiHelpers class +/// +public static class EssentialsWebApiHelpers { /// - /// EssentialsWebApiHelpers class + /// GetRequestBody method /// - public static class EssentialsWebApiHelpers + public static string GetRequestBody(this HttpCwsRequest request) { - /// - /// 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 { - var bytes = new byte[request.ContentLength]; + assembly.Name, + assembly.Version + }; + } - request.InputStream.Read(bytes, 0, request.ContentLength); - - return Encoding.UTF8.GetString(bytes, 0, bytes.Length); - } - - /// - /// MapToAssemblyObject method - /// - public static object MapToAssemblyObject(LoadedAssembly assembly) + /// + /// MapToDeviceListObject method + /// + public static object MapToDeviceListObject(IKeyed device) + { + return new { - return new - { - assembly.Name, - assembly.Version - }; - } + device.Key, + Name = (device is IKeyName) + ? (device as IKeyName).Name + : "---" + }; + } - /// - /// MapToDeviceListObject method - /// - public static object MapToDeviceListObject(IKeyed device) + /// + /// 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 { - return new - { - device.Key, - Name = (device is IKeyName) - ? (device as IKeyName).Name - : "---" - }; - } + DeviceKey = join.Key, + Joins = join.Value.Joins.Select(j => MapJoinDataCompleteToObject(j)) + }; + } - /// - /// MapJoinToObject method - /// - public static object MapJoinToObject(string key, JoinMapBaseAdvanced join) + /// + /// MapJoinDataCompleteToObject method + /// + public static object MapJoinDataCompleteToObject(KeyValuePair joinData) + { + return new { - var kp = new KeyValuePair(key, join); + 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() + }; + } - return MapJoinToObject(kp); - } + /// + /// MapDeviceTypeToObject method + /// + public static object MapDeviceTypeToObject(string key, DeviceFactoryWrapper device) + { + var kp = new KeyValuePair(key, device); - /// - /// MapJoinToObject method - /// - public static object MapJoinToObject(KeyValuePair join) + return MapDeviceTypeToObject(kp); + } + + /// + /// MapDeviceTypeToObject method + /// + public static object MapDeviceTypeToObject(KeyValuePair device) + { + return new { - 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() - }; - } + Type = device.Key, + Description = device.Value.Description, + CType = device.Value.Type == null ? "---" : device.Value.Type.ToString() + }; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiPropertiesConfig.cs index 9c00fd93..63e68544 100644 --- a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiPropertiesConfig.cs @@ -1,16 +1,15 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials.Core.Web +namespace PepperDash.Essentials.Core.Web; + +/// +/// Represents a EssentialsWebApiPropertiesConfig +/// +public class EssentialsWebApiPropertiesConfig { /// - /// Represents a EssentialsWebApiPropertiesConfig + /// Gets or sets the BasePath /// - public class EssentialsWebApiPropertiesConfig - { - /// - /// Gets or sets the BasePath - /// - [JsonProperty("basePath")] - public string BasePath { get; set; } - } + [JsonProperty("basePath")] + public string BasePath { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs index 3d3302cc..2bc8ce09 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs @@ -2,94 +2,92 @@ 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 +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +/// +/// Represents a AppDebugRequestHandler +/// +public class AppDebugRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a AppDebugRequestHandler - /// - public class AppDebugRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public AppDebugRequestHandler() + : base(true) { - /// - /// 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 + /// Handles GET method requests /// - public class AppDebug + /// + protected override void HandleGet(HttpCwsContext context) { - /// - /// Gets or sets the MinimumLevel - /// - [JsonProperty("minimumLevel", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(StringEnumConverter))] - public LogEventLevel MinimumLevel { get; set; } + 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; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugSessionRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugSessionRequestHandler.cs index 56e2b880..4dbd00a5 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugSessionRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugSessionRequestHandler.cs @@ -1,107 +1,94 @@ 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; -using PepperDash.Essentials.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class DebugSessionRequestHandler : WebApiBaseRequestHandler +{ + private readonly DebugWebsocketSink _sink = new DebugWebsocketSink(); + + public DebugSessionRequestHandler() + : base(true) + { + } + /// - /// Represents a DebugSessionRequestHandler + /// Gets details for a debug session /// - public class DebugSessionRequestHandler : WebApiBaseRequestHandler - { - - private readonly DebugWebsocketSink _sink = new DebugWebsocketSink(); - - /// - /// Constructor - /// - public DebugSessionRequestHandler() - : base(true) + /// + protected override void HandleGet(Crestron.SimplSharp.WebScripting.HttpCwsContext context) + { + var routeData = context.Request.RouteData; + if (routeData == null) { - } - - /// - /// 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 (!_sink.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 - _sink.StartServerAndSetPort(port); - Debug.SetWebSocketMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose); - } - - var url = _sink.Url; - - object data = new - { - url = _sink.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) - { - _sink.StopServer(); - - context.Response.StatusCode = 200; - context.Response.StatusDescription = "OK"; + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; context.Response.End(); - Debug.LogMessage(LogEventLevel.Information, "Websocket Debug Session Stopped"); + return; } + try + { + var ip = CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); + + var port = 0; + + if (!_sink.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 + _sink.StartServerAndSetPort(port); + Debug.SetWebSocketMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose); + } + + var url = _sink.Url; + + object data = new + { + url = _sink.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) + { + _sink.StopServer(); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.End(); + + Debug.LogMessage(LogEventLevel.Information, "Websocket Debug Session Stopped"); + } + } diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugWebsocketSink.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugWebsocketSink.cs index add30634..34d8b446 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugWebsocketSink.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugWebsocketSink.cs @@ -1,42 +1,41 @@ using System; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class DebugWebsocketSink { - public class DebugWebsocketSink + private bool _isRunning; + private string _url; + + public bool IsRunning => _isRunning; + public string Url => _url; + + public void StartServerAndSetPort(int port) { - private bool _isRunning; - private string _url; - - public bool IsRunning => _isRunning; - public string Url => _url; - - public void StartServerAndSetPort(int port) + try { - try - { - _url = $"ws://localhost:{port}"; - _isRunning = true; - // Implement actual server startup logic here - } - catch (Exception ex) - { - _isRunning = false; - throw new Exception($"Failed to start debug websocket server: {ex.Message}"); - } + _url = $"ws://localhost:{port}"; + _isRunning = true; + // Implement actual server startup logic here } - - public void StopServer() + catch (Exception ex) { - try - { - // Implement actual server shutdown logic here - _isRunning = false; - _url = null; - } - catch (Exception ex) - { - throw new Exception($"Failed to stop debug websocket server: {ex.Message}"); - } + _isRunning = false; + throw new Exception($"Failed to start debug websocket server: {ex.Message}"); + } + } + + public void StopServer() + { + try + { + // Implement actual server shutdown logic here + _isRunning = false; + _url = null; + } + catch (Exception ex) + { + throw new Exception($"Failed to stop debug websocket server: {ex.Message}"); } } } diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DefaultRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DefaultRequestHandler.cs index c0fec253..24ad97bc 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DefaultRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DefaultRequestHandler.cs @@ -1,11 +1,8 @@ using Crestron.SimplSharp.WebScripting; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ - /// - /// Represents a DefaultRequestHandler - /// +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class DefaultRequestHandler : WebApiBaseRequestHandler { /// @@ -117,5 +114,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.StatusDescription = "I'm a teapot"; context.Response.End(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs index 51b261fe..f0cefb1c 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs @@ -5,11 +5,8 @@ using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; using Serilog.Events; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ - /// - /// Represents a DevJsonRequestHandler - /// +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class DevJsonRequestHandler : WebApiBaseRequestHandler { /// @@ -29,25 +26,25 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers /// protected override void HandlePost(HttpCwsContext context) { - var routeData = context.Request.RouteData; + var routeData = context.Request.RouteData; - if(routeData == null) - { - context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; - context.Response.End(); + if(routeData == null) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); - return; - } + return; + } - if(!routeData.Values.TryGetValue("deviceKey", out var deviceKey)) - { - context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; - context.Response.End(); + if(!routeData.Values.TryGetValue("deviceKey", out var deviceKey)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); - return; - } + return; + } if (context.Request.ContentLength < 0) { @@ -71,11 +68,11 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers try { - var daw = new DeviceActionWrapper { DeviceKey = (string) deviceKey}; + var daw = new DeviceActionWrapper { DeviceKey = (string) deviceKey}; - JsonConvert.PopulateObject(data, daw); + JsonConvert.PopulateObject(data, daw); - Debug.LogMessage(LogEventLevel.Verbose, "Device Action Wrapper: {@wrapper}", null, daw); + Debug.LogMessage(LogEventLevel.Verbose, "Device Action Wrapper: {@wrapper}", null, daw); DeviceJsonApi.DoDeviceAction(daw); @@ -89,9 +86,8 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; - context.Response.Write(JsonConvert.SerializeObject(new { error = ex.Message }), false); + context.Response.Write(JsonConvert.SerializeObject(new { error = ex.Message }), false); context.Response.End(); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs index 31bfd6f9..420cd26c 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs @@ -3,52 +3,48 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class DevListRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a DevListRequestHandler - /// - public class DevListRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public DevListRequestHandler() + : base(true) { - /// - /// 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) { - } - - /// - /// 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.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(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs index 004ce5ed..f3bb5c1f 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs @@ -1,81 +1,76 @@ using System.Text; using Crestron.SimplSharp.WebScripting; -using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class DevMethodsRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a DevMethodsRequestHandler - /// - public class DevMethodsRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public DevMethodsRequestHandler() + : base(true) { - /// - /// 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) { - } - - /// - /// 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.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(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevPropsRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevPropsRequestHandler.cs index 2117619b..1d51b204 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevPropsRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevPropsRequestHandler.cs @@ -1,79 +1,74 @@ using System.Text; using Crestron.SimplSharp.WebScripting; -using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class DevPropsRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a DevPropsRequestHandler - /// - public class DevPropsRequestHandler : WebApiBaseRequestHandler - { - /// - /// Constructor - /// - /// - /// base(true) enables CORS support by default - /// - public DevPropsRequestHandler() - : base(true) - { - } + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public DevPropsRequestHandler() + : base(true) + { + } - /// - /// Handles GET method requests - /// - /// - protected override void HandleGet(HttpCwsContext context) + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + var routeData = context.Request.RouteData; + if (routeData == null) { - 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.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(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DisableAllStreamDebugRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DisableAllStreamDebugRequestHandler.cs index 172b8c4d..66c5c3a8 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DisableAllStreamDebugRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DisableAllStreamDebugRequestHandler.cs @@ -1,35 +1,31 @@ using Crestron.SimplSharp.WebScripting; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class DisableAllStreamDebugRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a DisableAllStreamDebugRequestHandler - /// - public class DisableAllStreamDebugRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public DisableAllStreamDebugRequestHandler() + : base(true) { - /// - /// Constructor - /// - /// - /// base(true) enables CORS support by default - /// - public DisableAllStreamDebugRequestHandler() - : base(true) - { - } + } - /// - /// Handles POST method requests - /// - /// - protected override void HandlePost(HttpCwsContext context) - { - DeviceManager.DisableAllDeviceStreamDebugging(); + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + DeviceManager.DisableAllDeviceStreamDebugging(); - context.Response.StatusCode = 200; - context.Response.StatusDescription = "OK"; - context.Response.End(); - } + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.End(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs index 593ce4e7..b52b0fd2 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs @@ -3,91 +3,87 @@ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class DoNotLoadConfigOnNextBootRequestHandler : WebApiBaseRequestHandler { /// - /// Represents a DoNotLoadConfigOnNextBootRequestHandler + /// Constructor /// - public class DoNotLoadConfigOnNextBootRequestHandler : WebApiBaseRequestHandler + /// + /// base(true) enables CORS support by default + /// + public DoNotLoadConfigOnNextBootRequestHandler() + : base(true) { - /// - /// 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 + /// Handles GET method requests /// - public class Data + /// + protected override void HandleGet(HttpCwsContext context) { - /// - /// Gets or sets the DoNotLoadConfigOnNextBoot - /// - [JsonProperty("doNotLoadConfigOnNextBoot", NullValueHandling = NullValueHandling.Ignore)] - public bool DoNotLoadConfigOnNextBoot { get; set; } + 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; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs index ca9eeb81..5e57b58b 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs @@ -3,103 +3,99 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class GetFeedbacksForDeviceRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a GetFeedbacksForDeviceRequestHandler - /// - public class GetFeedbacksForDeviceRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public GetFeedbacksForDeviceRequestHandler() + : base(true) { - /// - /// 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; } - /// - /// Handles GET method requests - /// - /// - protected override void HandleGet(HttpCwsContext context) + object deviceObj; + if (!routeData.Values.TryGetValue("deviceKey", out deviceObj)) { - var routeData = context.Request.RouteData; - if (routeData == null) + 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 { - 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 + FeedbackKey = feedback.Key, + Value = feedback.BoolValue }; - var js = JsonConvert.SerializeObject(responseObj, Formatting.Indented); + var intFeedback = + from feedback in device.Feedbacks.OfType() + where !string.IsNullOrEmpty(feedback.Key) + select new + { + FeedbackKey = feedback.Key, + Value = feedback.IntValue + }; - 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(); - } + 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(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForBridgeKeyRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForBridgeKeyRequestHandler.cs index 436215ca..ee7ec346 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForBridgeKeyRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForBridgeKeyRequestHandler.cs @@ -4,78 +4,74 @@ using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.Core.Bridges; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class GetJoinMapForBridgeKeyRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a GetJoinMapForBridgeKeyRequestHandler - /// - public class GetJoinMapForBridgeKeyRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public GetJoinMapForBridgeKeyRequestHandler() + : base(true) { - /// - /// 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; } - /// - /// Handles GET method requests - /// - /// - protected override void HandleGet(HttpCwsContext context) + object bridgeObj; + if (!routeData.Values.TryGetValue("bridgeKey", out bridgeObj)) { - 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.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(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForDeviceKeyRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForDeviceKeyRequestHandler.cs index 0cb81d38..54996b8c 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForDeviceKeyRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForDeviceKeyRequestHandler.cs @@ -3,96 +3,92 @@ using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.Core.Bridges; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class GetJoinMapForDeviceKeyRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a GetJoinMapForDeviceKeyRequestHandler - /// - public class GetJoinMapForDeviceKeyRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public GetJoinMapForDeviceKeyRequestHandler() + : base(true) { - /// - /// 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) { - } - - /// - /// 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.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(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutesHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutesHandler.cs index bd264a7a..c86777b3 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutesHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutesHandler.cs @@ -3,71 +3,49 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class GetRoutesHandler:WebApiBaseRequestHandler { - /// - /// Represents a GetRoutesHandler - /// - public class GetRoutesHandler:WebApiBaseRequestHandler - { - private HttpCwsRouteCollection routeCollection; - private string basePath; + 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(); - } + public GetRoutesHandler(HttpCwsRouteCollection routeCollection, string basePath) { + this.routeCollection = routeCollection; + this.basePath = basePath; } - /// - /// Represents a RoutesResponseObject - /// - public class RoutesResponseObject + protected override void HandleGet(HttpCwsContext context) { - /// - /// Gets or sets the Url - /// - [JsonProperty("url")] - public string Url { set; get; } + var currentIp = CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); - /// - /// Gets or sets the Routes - /// - [JsonProperty("routes")] - public HttpCwsRouteCollection Routes { get; set; } + 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(); } } + +public class RoutesResponseObject +{ + [JsonProperty("url")] + public string Url { set; get; } + + [JsonProperty("routes")] + public HttpCwsRouteCollection Routes { get; set; } +} diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutingPortsHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutingPortsHandler.cs index 8cee7e9e..b0020c75 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutingPortsHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutingPortsHandler.cs @@ -5,83 +5,66 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class GetRoutingPortsHandler : WebApiBaseRequestHandler { - /// - /// Represents a GetRoutingPortsHandler - /// - public class GetRoutingPortsHandler : WebApiBaseRequestHandler - { - /// - /// Constructor - /// - public GetRoutingPortsHandler() : base(true) { } + public GetRoutingPortsHandler() : base(true) { } - /// - /// Handles the GET request - /// - /// - protected override void HandleGet(HttpCwsContext context) + protected override void HandleGet(HttpCwsContext context) + { + var routeData = context.Request.RouteData; + + if (routeData == null) { - 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.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; context.Response.End(); - + return; } - } - internal class ReturnValue - { - /// - /// Gets or sets the InputPorts - /// - [JsonProperty("inputPorts", NullValueHandling = NullValueHandling.Ignore)] - public List InputPorts { get; set; } + 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(); - /// - /// Gets or sets the OutputPorts - /// - [JsonProperty("outputPorts", NullValueHandling = NullValueHandling.Ignore)] - public List OutputPorts { get; set; } } } + +internal class ReturnValue +{ + [JsonProperty("inputPorts", NullValueHandling = NullValueHandling.Ignore)] + public List InputPorts { get; set; } + + [JsonProperty("outputPorts", NullValueHandling = NullValueHandling.Ignore)] + public List OutputPorts { get; set; } +} diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs index f7088cb2..c8e02126 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs @@ -1,43 +1,32 @@ -using Crestron.SimplSharp.WebScripting; +using System.Linq; +using System.Text; +using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -using System.Linq; -using System.Text; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class GetTieLinesRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a GetTieLinesRequestHandler - /// - public class GetTieLinesRequestHandler : WebApiBaseRequestHandler + public GetTieLinesRequestHandler() : base(true) { } + + protected override void HandleGet(HttpCwsContext context) { - /// - /// Constructor - /// - public GetTieLinesRequestHandler() : base(true) { } - - /// - /// Handles the GET request - /// - /// - protected override void HandleGet(HttpCwsContext context) + var tieLineString = JsonConvert.SerializeObject(TieLineCollection.Default.Select((tl) => new { - 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(), - })); + 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(); + 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(); - } } } diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesByFilterRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesByFilterRequestHandler.cs index 2cabeb5e..fff21d17 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesByFilterRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesByFilterRequestHandler.cs @@ -3,69 +3,68 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +/// +/// Handles requests for types of devices based on a filter. The filter is used to determine which device factory to pull types from. The filter is passed as part of the URL and is accessed via the RouteData property of the HttpCwsContext. +/// +public class GetTypesByFilterRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a GetTypesByFilterRequestHandler - /// - public class GetTypesByFilterRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public GetTypesByFilterRequestHandler() + : base(true) { - /// - /// 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) { - } - - /// - /// 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.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(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesRequestHandler.cs index 6d011d23..e60700a1 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesRequestHandler.cs @@ -3,59 +3,58 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +/// +/// Handles requests for types of devices. This handler is used when no filter is needed to determine which device factory to pull types from. If a filter is needed, use the GetTypesByFilterRequestHandler instead. +/// +public class GetTypesRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a GetTypesRequestHandler - /// - public class GetTypesRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public GetTypesRequestHandler() + : base(true) { - /// - /// 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) { - } - - /// - /// 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.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(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/LoadConfigRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/LoadConfigRequestHandler.cs index 7706973e..adc68c66 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/LoadConfigRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/LoadConfigRequestHandler.cs @@ -1,42 +1,38 @@ -using Crestron.SimplSharp; -using Crestron.SimplSharp.WebScripting; -using Newtonsoft.Json; -using PepperDash.Core; +using Crestron.SimplSharp.WebScripting; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +/// +/// Handles requests to load the config. This is used when the config is loaded via the web API instead of at startup. This is typically used in conjunction with the SaveConfigRequestHandler to allow for saving and loading of the config via the web API. +/// +public class LoadConfigRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a LoadConfigRequestHandler - /// - public class LoadConfigRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public LoadConfigRequestHandler() + : base(true) { - /// - /// 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(); - } + } + + /// + /// 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(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/ReportVersionsRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/ReportVersionsRequestHandler.cs index ace863ab..00c33044 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/ReportVersionsRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/ReportVersionsRequestHandler.cs @@ -3,50 +3,49 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +/// +/// Handles requests for reporting versions of loaded assemblies. This is used to report the versions of the assemblies that are currently loaded in the system, which can be helpful for debugging and support purposes. +/// +public class ReportVersionsRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a ReportVersionsRequestHandler - /// - public class ReportVersionsRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public ReportVersionsRequestHandler() + : base(true) { - /// - /// 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) { - } - - /// - /// 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.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(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/RestartProgramRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/RestartProgramRequestHandler.cs index 9f853e61..a094657b 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/RestartProgramRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/RestartProgramRequestHandler.cs @@ -1,41 +1,39 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; -using Newtonsoft.Json; -using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +/// +/// Handles requests to restart the program. +/// This is used when the program needs to be restarted via the web API instead of manually restarting the program. +/// +public class RestartProgramRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a RestartProgramRequestHandler - /// - public class RestartProgramRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public RestartProgramRequestHandler() + : base(true) { - /// - /// 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(); - } + } + + /// + /// 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(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs index dd4f416f..bb0525d9 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs @@ -4,228 +4,230 @@ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +/// +/// Handles requests for setting stream debugging on devices that support it. +/// The request is expected to be a POST with a JSON body that includes the device key, the desired debug setting, and an optional timeout in minutes. +/// The handler will attempt to find the device by key, cast it to IStreamDebugging, and then set the debugging according to the provided setting and timeout. +/// If any step fails, an appropriate HTTP error response is returned. +/// +public class SetDeviceStreamDebugRequestHandler : WebApiBaseRequestHandler { /// - /// Represents a SetDeviceStreamDebugRequestHandler + /// Handles CONNECT method requests /// - public class SetDeviceStreamDebugRequestHandler : WebApiBaseRequestHandler + /// + protected override void HandleConnect(HttpCwsContext context) { - /// - /// 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(); - } + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); } - /// - /// Configuration class for SetDeviceStreamDebugRequestHandler + /// Handles DELETE method requests /// - public class SetDeviceStreamDebugConfig + /// + protected override void HandleDelete(HttpCwsContext context) { - /// - /// Gets or sets the DeviceKey - /// - [JsonProperty("deviceKey", NullValueHandling = NullValueHandling.Include)] - public string DeviceKey { get; set; } + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } - /// - /// Gets or sets the Setting - /// - [JsonProperty("setting", NullValueHandling = NullValueHandling.Include)] - public string Setting { get; set; } + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } - /// - /// Gets or sets the Timeout - /// - [JsonProperty("timeout")] - public int Timeout { get; set; } + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } - /// - /// Constructor - /// - public SetDeviceStreamDebugConfig() + /// + /// 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) { - DeviceKey = null; - Setting = null; - Timeout = 15; + 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; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/ShowConfigRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/ShowConfigRequestHandler.cs index 4964822e..e053ccce 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/ShowConfigRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/ShowConfigRequestHandler.cs @@ -3,38 +3,39 @@ using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.Core.Config; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +/// +/// Handles requests to show the current config. +/// This is used to display the current config via the web API. +/// The config is returned as a JSON string. +/// +public class ShowConfigRequestHandler : WebApiBaseRequestHandler { - /// - /// Represents a ShowConfigRequestHandler - /// - public class ShowConfigRequestHandler : WebApiBaseRequestHandler + /// + /// Constructor + /// + /// + /// base(true) enables CORS support by default + /// + public ShowConfigRequestHandler() + : base(true) { - /// - /// 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); + /// + /// 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(); - } + 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(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs b/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs index c0f8ac1e..9b8dd2e5 100644 --- a/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs +++ b/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs @@ -6,152 +6,128 @@ using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common +namespace PepperDash.Essentials.Devices.Common; + +/// +/// Represents and audio endpoint +/// +public class GenericAudioOut : EssentialsDevice, IRoutingSink +{ + public RoutingInputPort CurrentInputPort => AnyAudioIn; + + public event SourceInfoChangeHandler CurrentSourceChange; + + public string CurrentSourceInfoKey { get; set; } + 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 { /// - /// Represents and audio endpoint + /// Gets the volume device key /// - 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 - } - + public string VolumeDeviceKey { get; private set; } + /// + /// Gets the volume zone + /// + public uint VolumeZone { get; private set; } /// - /// Represents a GenericAudioOutWithVolume + /// Gets the volume device /// - public class GenericAudioOutWithVolume : GenericAudioOut, IHasVolumeDevice + public IBasicVolumeControls VolumeDevice { - /// - /// 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 { - get - { - var dev = DeviceManager.GetDeviceForKey(VolumeDeviceKey); - if (dev is IAudioZones) - return (dev as IAudioZones).Zone[VolumeZone]; - else return dev as IBasicVolumeControls; - } + 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 + /// Constructor - adds the name to the attached audio device, if appropriate. /// - public class GenericAudioOutWithVolumeFactory : EssentialsDeviceFactory + /// + /// + /// + /// + public GenericAudioOutWithVolume(string key, string name, string audioDevice, uint zone) + : base(key, name) { - /// - /// 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); - } + VolumeDeviceKey = audioDevice; + VolumeZone = zone; } +} + +public class GenericAudioOutWithVolumeFactory : EssentialsDeviceFactory +{ + public GenericAudioOutWithVolumeFactory() + { + TypeNames = new List() { "genericaudiooutwithvolume" }; + } + + 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); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs index 7f760bc3..dc0f98a6 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs @@ -4,117 +4,96 @@ using System.Linq; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Codec; -namespace PepperDash.Essentials.Devices.Common.AudioCodec +namespace PepperDash.Essentials.Devices.Common.AudioCodec; + +public abstract class AudioCodecBase : EssentialsDevice, IHasDialer, IUsageTracking, IAudioCodecInfo { + + public event EventHandler CallStatusChange; + + public AudioCodecInfo CodecInfo { get; protected set; } + + #region IUsageTracking Members + /// - /// Abstract base class for audio codec devices + /// This object can be added by outside users of this class to provide usage tracking + /// for various services /// - public abstract class AudioCodecBase : EssentialsDevice, IHasDialer, IUsageTracking, IAudioCodecInfo + public UsageTracking UsageTracker { get; set; } + + #endregion + + /// + /// Returns true when any call is not in state Unknown, Disconnecting, Disconnected + /// + public bool IsInCall { - - /// - /// 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 { - get - { - bool value; + bool value; - if (ActiveCalls != null) - value = ActiveCalls.Any(c => c.IsActiveCall); - else - value = false; - return 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 } + + // In most cases only a single call can be active + public List ActiveCalls { get; set; } + + 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); + + } + + /// + /// + /// + /// + /// + /// + 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 } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs index 3e6b0418..6d45515e 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs @@ -1,24 +1,18 @@ -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; } - } +namespace PepperDash.Essentials.Devices.Common.AudioCodec; + +/// +/// Implements a common set of data about a codec +/// +public interface IAudioCodecInfo +{ + AudioCodecInfo CodecInfo { get; } +} + +/// +/// Stores general information about a codec +/// +public abstract class AudioCodecInfo +{ + public abstract string PhoneNumber { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs index 946c2053..df62d915 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs @@ -1,17 +1,14 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.AudioCodec +namespace PepperDash.Essentials.Devices.Common.AudioCodec; + +/// +/// Interface for devices that have an audio codec. +/// +public interface IHasAudioCodec:IHasInCallFeedback { /// - /// For rooms that have audio codec + /// Gets the audio codec device /// - public interface IHasAudioCodec : IHasInCallFeedback - { - /// - /// Gets the audio codec device - /// - AudioCodecBase AudioCodec { get; } - - //List ActiveCalls { get; } - } + AudioCodecBase AudioCodec { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs index 48235a45..b32340af 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs @@ -6,169 +6,121 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Devices.Common.Codec; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.AudioCodec +namespace PepperDash.Essentials.Devices.Common.AudioCodec; + +public class MockAC : AudioCodecBase { - /// - /// Represents a MockAC - /// - public class MockAC : AudioCodecBase + public MockAC(string key, string name, MockAcPropertiesConfig props) + : base(key, name) { - /// - /// 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 = new MockAudioCodecInfo(); - CodecInfo.PhoneNumber = props.PhoneNumber; - } + CodecInfo.PhoneNumber = props.PhoneNumber; + } - /// - /// Dial method - /// - /// - public override void Dial(string number) + public override void Dial(string number) + { + if (!IsInCall) { - if (!IsInCall) + Debug.LogMessage(LogEventLevel.Debug, this, "Dial: {0}", number); + var call = new CodecActiveCallItem() { - 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" - }; + 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); - } + OnCallStatusChange(call); + } + else + { + Debug.LogMessage(LogEventLevel.Debug, this, "Already in call. Cannot dial new call."); + } + } + + public override void EndCall(CodecActiveCallItem call) + { + Debug.LogMessage(LogEventLevel.Debug, this, "EndCall"); + ActiveCalls.Remove(call); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); + } + + 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); + } + } + + public override void AcceptCall(CodecActiveCallItem call) + { + Debug.LogMessage(LogEventLevel.Debug, this, "AcceptCall"); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); + } + + public override void RejectCall(CodecActiveCallItem call) + { + Debug.LogMessage(LogEventLevel.Debug, this, "RejectCall"); + ActiveCalls.Remove(call); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); + } + + public override void SendDtmf(string s) + { + Debug.LogMessage(LogEventLevel.Debug, this, "BEEP BOOP SendDTMF: {0}", s); } /// - /// Represents a MockAudioCodecInfo + /// /// - public class MockAudioCodecInfo : AudioCodecInfo + /// + public void TestIncomingAudioCall(string number) { - string _phoneNumber; - - /// - public override string PhoneNumber - { - get - { - return _phoneNumber; - } - set - { - _phoneNumber = value; - } - } + 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 MockACFactory - /// - public class MockACFactory : EssentialsDeviceFactory - { - /// - /// Constructor for MockACFactory - /// - public MockACFactory() - { - TypeNames = new List() { "mockac" }; - } +} - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) +public class MockAudioCodecInfo : AudioCodecInfo +{ + string _phoneNumber; + + public override string PhoneNumber + { + get { - 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); + return _phoneNumber; + } + set + { + _phoneNumber = value; } } +} +public class MockACFactory : EssentialsDeviceFactory +{ + public MockACFactory() + { + TypeNames = new List() { "mockac" }; + } + + 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); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs index 0deaca97..7ac205bb 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs @@ -1,16 +1,9 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials.Devices.Common.AudioCodec +namespace PepperDash.Essentials.Devices.Common.AudioCodec; + +public class MockAcPropertiesConfig { - /// - /// Represents a MockAcPropertiesConfig - /// - public class MockAcPropertiesConfig - { - /// - /// Gets or sets the PhoneNumber - /// - [JsonProperty("phoneNumber")] - public string PhoneNumber { get; set; } - } + [JsonProperty("phoneNumber")] + public string PhoneNumber { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs index e2e15668..a7b880c9 100644 --- a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs @@ -13,337 +13,266 @@ using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.Presets; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Cameras +namespace PepperDash.Essentials.Devices.Common.Cameras; + +public enum eCameraCapabilities { - /// - /// Enumeration of eCameraCapabilities values - /// - public enum eCameraCapabilities + None = 0, + Pan = 1, + Tilt = 2, + Zoom = 4, + Focus = 8 +} + +public abstract class CameraBase : ReconfigurableDevice, IRoutingOutputs + { + [JsonProperty("controlMode", NullValueHandling = NullValueHandling.Ignore)] + public eCameraControlMode ControlMode { get; protected set; } + + #region IRoutingOutputs Members + + [JsonIgnore] + public RoutingPortCollection OutputPorts { get; protected set; } + + #endregion + + [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] + public bool CanPan { - /// - /// 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 + get + { + return (Capabilities & eCameraCapabilities.Pan) == eCameraCapabilities.Pan; + } + } + [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] + public bool CanTilt + { + get + { + return (Capabilities & eCameraCapabilities.Tilt) == eCameraCapabilities.Tilt; + } + } + [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] + public bool CanZoom + { + get + { + return (Capabilities & eCameraCapabilities.Zoom) == eCameraCapabilities.Zoom; + } + } + [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] + public bool CanFocus + { + get + { + return (Capabilities & eCameraCapabilities.Focus) == eCameraCapabilities.Focus; + } } - /// - /// Abstract base class for camera devices that provides common camera functionality and capabilities - /// - public abstract class CameraBase : ReconfigurableDevice, IRoutingOutputs + // A bitmasked value to indicate the movement capabilites of this camera + protected eCameraCapabilities Capabilities { get; set; } + + protected CameraBase(DeviceConfig config) : base(config) + { + OutputPorts = new RoutingPortCollection(); + + ControlMode = eCameraControlMode.Manual; + + } + + protected CameraBase(string key, string name) : + this (new DeviceConfig{Name = name, Key = key}) { - /// - /// Gets or sets the ControlMode - /// - [JsonProperty("controlMode", NullValueHandling = NullValueHandling.Ignore)] - public eCameraControlMode ControlMode { get; protected set; } + + } - #region IRoutingOutputs Members + protected void LinkCameraToApi(CameraBase cameraDevice, BasicTriList trilist, uint joinStart, string joinMapKey, + EiscApiAdvanced bridge) + { + CameraControllerJoinMap joinMap = new CameraControllerJoinMap(joinStart); - /// - /// 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 + if (bridge != null) { - get - { - return (Capabilities & eCameraCapabilities.Pan) == eCameraCapabilities.Pan; - } + 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."); } - /// - /// Gets a value indicating whether this camera supports tilt movement - /// - [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] - public bool CanTilt + var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); + + if (customJoins != null) { - get - { - return (Capabilities & eCameraCapabilities.Tilt) == eCameraCapabilities.Tilt; - } + joinMap.SetCustomJoinData(customJoins); } - /// - /// Gets a value indicating whether this camera supports zoom functionality - /// - [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] - public bool CanZoom + 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) { - get + trilist.SetBoolSigAction(joinMap.PanLeft.JoinNumber, (b) => { - 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) { - 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]); + ptzCamera.PanLeft(); } - } - - 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) => + else { - SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist); + 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); + }; - 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 + private void SendCameraPresetNamesToApi(IHasCameraPresets presetsCamera, CameraControllerJoinMap joinMap, BasicTriList trilist) { - /// - /// 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) + 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); } } + } + + +public class CameraPreset : PresetBase +{ + public CameraPreset(int id, string description, bool isDefined, bool isDefinable) + : base(id, description, isDefined, isDefinable) + { + + } +} /// @@ -361,22 +290,12 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// public ControlPropertiesConfig Control { get; set; } - /// - /// Gets or sets the SupportsAutoMode - /// - [JsonProperty("supportsAutoMode")] - public bool SupportsAutoMode { get; set; } + [JsonProperty("supportsAutoMode")] + public bool SupportsAutoMode { get; set; } - /// - /// Gets or sets the SupportsOffMode - /// - [JsonProperty("supportsOffMode")] - public bool SupportsOffMode { get; set; } + [JsonProperty("supportsOffMode")] + public bool SupportsOffMode { get; set; } - /// - /// Gets or sets the Presets - /// - [JsonProperty("presets")] - public List Presets { get; set; } - } -} \ No newline at end of file + [JsonProperty("presets")] + public List Presets { get; set; } + } diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs index 126bcd27..e1ca7102 100644 --- a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs @@ -12,833 +12,704 @@ using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Cameras +namespace PepperDash.Essentials.Devices.Common.Cameras; + +/// +/// Camera driver for cameras that use the VISCA control protocol. This driver supports both IP and RS-232 control depending on the communication method passed in. It also supports pan/tilt speed control, presets, and focus control. +/// +public class CameraVisca : CameraBase, IHasCameraPtzControl, ICommunicationMonitor, IHasCameraPresets, IHasPowerControlWithFeedback, IBridgeAdvanced, IHasCameraFocusControl, IHasAutoFocusMode { + private readonly CameraViscaPropertiesConfig PropertiesConfig; + /// - /// Represents a CameraVisca + /// Gets or sets the Communication /// - public class CameraVisca : CameraBase, IHasCameraPtzControl, ICommunicationMonitor, IHasCameraPresets, IHasPowerControlWithFeedback, IBridgeAdvanced, IHasCameraFocusControl, IHasAutoFocusMode + 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; + public byte ResponseID; + + /// + /// Slow speed value for pan movement + /// + public byte PanSpeedSlow = 0x10; + + /// + /// Slow speed value for tilt movement + /// + public byte TiltSpeedSlow = 0x10; + + public byte PanSpeedFast = 0x13; + public byte TiltSpeedFast = 0x13; + + // private bool IsMoving; + private bool IsZooming; + + bool _powerIsOn; + public bool PowerIsOn { - 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 { - get + return _powerIsOn; + } + private set + { + if (value != _powerIsOn) { - return _powerIsOn; - } - private set - { - if (value != _powerIsOn) - { - _powerIsOn = value; - PowerIsOnFeedback.FireUpdate(); - CameraIsOffFeedback.FireUpdate(); - } + _powerIsOn = value; + PowerIsOnFeedback.FireUpdate(); + CameraIsOffFeedback.FireUpdate(); } } + } - const byte ZoomInCmd = 0x02; - const byte ZoomOutCmd = 0x03; - const byte ZoomStopCmd = 0x00; + 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 + /// + /// 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; + long FastSpeedHoldTimeMs = 2000; - byte[] IncomingBuffer = new byte[] { }; + 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) : + public BoolFeedback PowerIsOnFeedback { get; private set; } + 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) { - 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); + // 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(() => { return PowerIsOn; }); + CameraIsOffFeedback = new BoolFeedback(() => { return !PowerIsOn; }); - /// - /// Sets up camera speed values based on config - /// - void SetupCameraSpeeds() + if (props.CommunicationMonitorProperties != null) { - if (PropertiesConfig.FastSpeedHoldTimeMs > 0) - { - FastSpeedHoldTimeMs = PropertiesConfig.FastSpeedHoldTimeMs; - } + CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties); + } + else + { + CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 20000, 120000, 300000, "\x81\x09\x04\x00\xFF"); + } + DeviceManager.AddDevice(CommunicationMonitor); + } - 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; - } + /// + /// Sets up camera speed values based on config + /// + void SetupCameraSpeeds() + { + if (PropertiesConfig.FastSpeedHoldTimeMs > 0) + { + FastSpeedHoldTimeMs = PropertiesConfig.FastSpeedHoldTimeMs; } - /// - /// CustomActivate method - /// - /// - public override bool CustomActivate() + if (PropertiesConfig.PanSpeedSlow > 0) { - 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; + PanSpeedSlow = (byte)PropertiesConfig.PanSpeedSlow; + } + if (PropertiesConfig.PanSpeedFast > 0) + { + PanSpeedFast = (byte)PropertiesConfig.PanSpeedFast; } - /// - /// LinkToApi method - /// - public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + if (PropertiesConfig.TiltSpeedSlow > 0) { - LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); + TiltSpeedSlow = (byte)PropertiesConfig.TiltSpeedSlow; } - - void Socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) + if (PropertiesConfig.TiltSpeedFast > 0) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString()); - - if (e.Client.IsConnected) - { - - } - else - { - - } + TiltSpeedFast = (byte)PropertiesConfig.TiltSpeedFast; } + } + + public override bool CustomActivate() + { + Communication.Connect(); - void SendBytes(byte[] b) + CommunicationMonitor.StatusChange += (o, a) => { Debug.LogMessage(LogEventLevel.Verbose, this, "Communication monitor state: {0}", CommunicationMonitor.Status); }; + CommunicationMonitor.Start(); + + + 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, "Sending:{0}", ComTextHelper.GetEscapedText(b)); + Debug.LogMessage(LogEventLevel.Verbose, this, "Received:{0}", ComTextHelper.GetEscapedText(newBytes)); - Communication.SendBytes(b); - } + byte[] message = new byte[] { }; - void Communication_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e) - { - var newBytes = new byte[IncomingBuffer.Length + e.Bytes.Length]; - - try + // Search for the delimiter 0xFF character + for (int i = 0; i < newBytes.Length; i++) { - // 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) { - 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(); - } + // 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; } - if (message.Length > 0) + switch (message[1]) { - // Check for matching ID - if (message[0] != ResponseID) - { - return; - } + case 0x40: + { + // ACK received + Debug.LogMessage(LogEventLevel.Verbose, this, "ACK Received"); + break; + } + case 0x50: + { - switch (message[1]) - { - case 0x40: + if (message[2] == 0xFF) { - // ACK received - Debug.LogMessage(LogEventLevel.Verbose, this, "ACK Received"); - break; + // Completion received + Debug.LogMessage(LogEventLevel.Verbose, this, "Completion Received"); } - case 0x50: + else { - - if (message[2] == 0xFF) + // Inquiry response received. Dequeue the next response handler and invoke it + if (InquiryResponseQueue.Count > 0) { - // Completion received - Debug.LogMessage(LogEventLevel.Verbose, this, "Completion Received"); + var inquiryAction = InquiryResponseQueue.Dequeue(); + + inquiryAction.Invoke(message.Skip(2).ToArray()); } 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."); - } + Debug.LogMessage(LogEventLevel.Verbose, this, "Response Queue is empty. Nothing to dequeue."); } - - break; } - case 0x60: + + break; + } + case 0x60: + { + // Error message + + switch (message[2]) { - // 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; + 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; + } } - } - - if (message == new byte[] { ResponseID, 0x50, 0x02, 0xFF }) - { - PowerIsOn = true; - } - else if (message == new byte[] { ResponseID, 0x50, 0x03, 0xFF }) - { - PowerIsOn = false; - } - + break; + } } - } - 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) + if (message == new byte[] { ResponseID, 0x50, 0x02, 0xFF }) { - StopSpeedTimer(); + PowerIsOn = true; + } + else if (message == new byte[] { ResponseID, 0x50, 0x03, 0xFF }) + { + PowerIsOn = false; } - // Start the timer to send fast speed if still moving after FastSpeedHoldTime elapses - SpeedTimer = new CTimer((o) => SendPanTiltCommand(GetPanTiltCommand(cmd, true), true), FastSpeedHoldTimeMs); } } + catch (Exception err) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Error parsing feedback: {0}", err); + } + finally + { + // Save whatever partial message is here + IncomingBuffer = newBytes; + } + } - private void StopSpeedTimer() + /// + /// Sends a pan/tilt command. If the command is not for fastSpeed then it starts a timer to initiate fast speed. + /// + /// + /// + private void SendPanTiltCommand(byte[] cmd, bool fastSpeedEnabled) + { + SendBytes(GetPanTiltCommand(cmd, fastSpeedEnabled)); + + if (!fastSpeedEnabled) { 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 }); + + // Start the timer to send fast speed if still moving after FastSpeedHoldTime elapses + SpeedTimer = new CTimer((o) => SendPanTiltCommand(GetPanTiltCommand(cmd, true), true), FastSpeedHoldTimeMs); } - #region IHasCameraPresets Members + } - /// - /// Event that is raised when the presets list has changed - /// - public event EventHandler PresetsListHasChanged; - - /// - /// Raises the PresetsListHasChanged event - /// - protected void OnPresetsListHasChanged() + private void StopSpeedTimer() + { + if (SpeedTimer != null) { - var handler = PresetsListHasChanged; - if (handler == null) - return; + SpeedTimer.Stop(); + SpeedTimer.Dispose(); + SpeedTimer = null; + } + } - handler.Invoke(this, EventArgs.Empty); + /// + /// 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; } - /// - /// Gets or sets the Presets - /// - public List Presets { get; private set; } + var temp = new byte[] { ID, 0x01, 0x06, 0x01, panSpeed, tiltSpeed }; + int length = temp.Length + cmd.Length + 1; - /// - /// PresetSelect method - /// - public void PresetSelect(int preset) + 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); + } + + public void PowerOn() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x00, 0x02, 0xFF }); + SendPowerQuery(); + } + + void HandlePowerResponse(byte[] response) + { + switch (response[0]) { - RecallPreset(preset); + case 0x02: + { + PowerIsOn = true; + break; + } + case 0x03: + { + PowerIsOn = false; + break; + } } + } - /// - /// PresetStore method - /// - public void PresetStore(int preset, string description) - { - SavePreset(preset); - } + public void PowerOff() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x00, 0x03, 0xFF }); + SendPowerQuery(); + } - - #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() - { + public void PowerToggle() + { + if (PowerIsOnFeedback.BoolValue) PowerOff(); - } - - #endregion + else + PowerOn(); } + public void PanLeft() + { + SendPanTiltCommand(new byte[] { 0x01, 0x03 }, false); + // IsMoving = true; + } + public void PanRight() + { + SendPanTiltCommand(new byte[] { 0x02, 0x03 }, false); + // IsMoving = true; + } + public void PanStop() + { + Stop(); + } + public void TiltDown() + { + SendPanTiltCommand(new byte[] { 0x03, 0x02 }, false); + // IsMoving = true; + } + public void TiltUp() + { + SendPanTiltCommand(new byte[] { 0x03, 0x01 }, false); + // IsMoving = true; + } + public void TiltStop() + { + Stop(); + } + + private void SendZoomCommand(byte cmd) + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x07, cmd, 0xFF }); + } + + + public void ZoomIn() + { + SendZoomCommand(ZoomInCmd); + IsZooming = true; + } + public void ZoomOut() + { + SendZoomCommand(ZoomOutCmd); + IsZooming = true; + } + public void ZoomStop() + { + Stop(); + } + + public void Stop() + { + if (IsZooming) + { + SendZoomCommand(ZoomStopCmd); + IsZooming = false; + } + else + { + StopSpeedTimer(); + SendPanTiltCommand(new byte[] { 0x03, 0x03 }, false); + // IsMoving = false; + } + } + 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 }); + } + public void RecallPreset(int presetNumber) + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x3F, 0x02, (byte)presetNumber, 0xFF }); + } + public void SavePreset(int presetNumber) + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x3F, 0x01, (byte)presetNumber, 0xFF }); + } + + #region IHasCameraPresets Members + + public event EventHandler PresetsListHasChanged; + /// - /// Represents a CameraViscaFactory + /// Raises the PresetsListHasChanged event /// - public class CameraViscaFactory : EssentialsDeviceFactory + protected void OnPresetsListHasChanged() { - /// - /// Initializes a new instance of the CameraViscaFactory class - /// - public CameraViscaFactory() - { - TypeNames = new List() { "cameravisca" }; - } + var handler = PresetsListHasChanged; + if (handler == null) + return; - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) + handler.Invoke(this, EventArgs.Empty); + } + + public List Presets { get; private set; } + + public void PresetSelect(int preset) + { + RecallPreset(preset); + } + + public void PresetStore(int preset, string description) + { + SavePreset(preset); + } + + + #endregion + + #region IHasCameraFocusControl Members + + public void FocusNear() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x03, 0xFF }); + } + + public void FocusFar() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x02, 0xFF }); + } + + public void FocusStop() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x00, 0xFF }); + } + + public void TriggerAutoFocus() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x18, 0x01, 0xFF }); + SendAutoFocusQuery(); + } + + #endregion + + #region IHasAutoFocus Members + + public void SetFocusModeAuto() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x02, 0xFF }); + SendAutoFocusQuery(); + } + + public void SetFocusModeManual() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x03, 0xFF }); + SendAutoFocusQuery(); + } + + 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]) { - 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); + case 0x02: + { + // Auto Mode + PowerIsOn = true; + break; + } + case 0x03: + { + // Manual Mode + PowerIsOn = false; + break; + } } } + #region IHasCameraOff Members + + public BoolFeedback CameraIsOffFeedback { get; private set; } + + + public void CameraOff() + { + PowerOff(); + } + + #endregion +} + +public class CameraViscaFactory : EssentialsDeviceFactory +{ + public CameraViscaFactory() + { + TypeNames = new List() { "cameravisca" }; + } + + 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); + } +} + + +public class CameraViscaPropertiesConfig : CameraPropertiesConfig +{ + /// + /// Control ID of the camera (1-7) + /// + [JsonProperty("id")] + public uint Id { get; set; } /// - /// Represents a CameraViscaPropertiesConfig + /// Slow Pan speed (0-18) /// - public class CameraViscaPropertiesConfig : CameraPropertiesConfig - { - /// - /// Control ID of the camera (1-7) - /// Gets or sets the Id - /// - [JsonProperty("id")] - public uint Id { get; set; } + [JsonProperty("panSpeedSlow")] + public uint PanSpeedSlow { 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; } - /// - /// Fast Pan speed (0-18) - /// - [JsonProperty("panSpeedFast")] - public uint PanSpeedFast { get; set; } + /// + /// Slow tilt speed (0-18) + /// + [JsonProperty("tiltSpeedSlow")] + public uint TiltSpeedSlow { 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; } - /// - /// 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; } - - } + /// + /// Time a button must be held before fast speed is engaged (Milliseconds) + /// + [JsonProperty("fastSpeedHoldTimeMs")] + public uint FastSpeedHoldTimeMs { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs index 0234a405..2fcdb9aa 100644 --- a/src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs @@ -1,34 +1,34 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Devices.Common.Cameras +namespace PepperDash.Essentials.Devices.Common.Cameras; + + +/// +/// Describes a camera with preset functionality +/// +public interface IHasCameraPresets { /// - /// Describes a camera with preset functionality + /// Event that is raised when the presets list has changed /// - public interface IHasCameraPresets - { - /// - /// Event that is raised when the presets list has changed - /// - event EventHandler PresetsListHasChanged; + event EventHandler PresetsListHasChanged; - /// - /// Gets the list of camera presets - /// - List Presets { get; } + /// + /// Gets the list of camera presets + /// + List Presets { get; } - /// - /// Selects the specified preset - /// - /// The preset number to select - void PresetSelect(int preset); + /// + /// 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); - } -} \ No newline at end of file + /// + /// 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); +} diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs b/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs index 134dc7b5..b98cb4e7 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs @@ -1,90 +1,89 @@ using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.Codec.Cisco +namespace PepperDash.Essentials.Devices.Common.Codec.Cisco; + +/// +/// Describes the available tracking modes for a Cisco codec's Presenter Track feature. +/// +public enum ePresenterTrackMode { /// - /// Describes the available tracking modes for a Cisco codec's Presenter Track feature. + /// Presenter Track is turned off. /// - 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 - } + 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; } + /// - /// Describes the Presenter Track controls for a Cisco codec. + /// Feedback indicating whether Presenter Track is available. /// - public interface IPresenterTrack : IKeyed - { - /// - /// - /// - bool PresenterTrackAvailability { get; } + BoolFeedback PresenterTrackAvailableFeedback { 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 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 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 background - /// - BoolFeedback PresenterTrackStatusBackgroundFeedback { get; } + /// + /// Feedback indicating the current status of Presenter Track is persistent + /// + BoolFeedback PresenterTrackStatusPersistentFeedback { get; } - /// - /// Feedback indicating the current status of Presenter Track is persistent - /// - BoolFeedback PresenterTrackStatusPersistentFeedback { get; } + /// + /// Indicates the current status of Presenter Track. + /// + bool PresenterTrackStatus { get; } - /// - /// Indicates the current status of Presenter Track. - /// - bool PresenterTrackStatus { get; } + /// + /// Turns off Presenter Track. + /// + void PresenterTrackOff(); - /// - /// Turns off Presenter Track. - /// - void PresenterTrackOff(); + /// + /// Turns on Presenter Track in follow mode. + /// + void PresenterTrackFollow(); - /// - /// Turns on Presenter Track in follow mode. - /// - void PresenterTrackFollow(); + /// + /// Turns on Presenter Track in background mode. + /// + void PresenterTrackBackground(); - /// - /// Turns on Presenter Track in background mode. - /// - void PresenterTrackBackground(); - - /// - /// Turns on Presenter Track in persistent mode. - /// - void PresenterTrackPersistent(); - } + /// + /// Turns on Presenter Track in persistent mode. + /// + void PresenterTrackPersistent(); } diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs b/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs index 522e6ad2..5e4726b2 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs @@ -1,35 +1,34 @@ using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.Codec.Cisco +namespace PepperDash.Essentials.Devices.Common.Codec.Cisco; + +/// +/// Describes the available tracking modes for a Cisco codec +/// +public interface ISpeakerTrack : IKeyed { /// - /// Describes the available tracking modes for a Cisco codec + /// Indicates whether Speaker Track is available on the codec. /// - public interface ISpeakerTrack : IKeyed - { - /// - /// Indicates whether Speaker Track is available on the codec. - /// - bool SpeakerTrackAvailability { get; } + bool SpeakerTrackAvailability { get; } - /// - /// - /// - BoolFeedback SpeakerTrackAvailableFeedback { get; } + /// + /// + /// + BoolFeedback SpeakerTrackAvailableFeedback { get; } - /// - /// Feedback indicating the current status of Speaker Track is off - /// - bool SpeakerTrackStatus { 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(); - } + /// + /// Turns Speaker Track off + /// + void SpeakerTrackOff(); + /// + /// Turns Speaker Track on + /// + void SpeakerTrackOn(); } diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs b/src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs index 23a39f29..b10e816b 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs @@ -1,105 +1,100 @@ - - -using System; - +using System; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; +/// +/// Represents an active call item for a codec, including details such as name, number, type, status, direction, and duration. +/// +public class CodecActiveCallItem { /// - /// Represents a CodecActiveCallItem + /// The name associated with the call, if available. /// - 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); - } - } - } + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name { get; set; } /// - /// Represents a CodecCallStatusItemChangeEventArgs + /// The phone number associated with the call, if available. /// - public class CodecCallStatusItemChangeEventArgs : EventArgs - { - /// - /// Gets or sets the CallItem - /// - public CodecActiveCallItem CallItem { get; private set; } + [JsonProperty("number", NullValueHandling = NullValueHandling.Ignore)] + public string Number { get; set; } - /// - /// Initializes a new instance of the CodecCallStatusItemChangeEventArgs class - /// - /// The call item that changed - public CodecCallStatusItemChangeEventArgs(CodecActiveCallItem item) + /// + /// The type of the call, such as audio or video. This is an optional property and may be null if the type is unknown or not applicable. + /// + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] + public eCodecCallType Type { get; set; } + + /// + /// The current status of the call, such as active, on hold, or disconnected. This is an optional property and may be null if the status is unknown or not applicable. + /// + [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] + public eCodecCallStatus Status { get; set; } + + /// + /// The direction of the call, such as incoming or outgoing. This is an optional property and may be null if the direction is unknown or not applicable. + /// + [JsonProperty("direction", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] + public eCodecCallDirection Direction { get; set; } + + /// + /// A unique identifier for the call, if available. This can be used to track the call across different events and status changes. This is an optional property and may be null if an identifier is not available or applicable. + /// + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public string Id { get; set; } + + /// + /// Indicates whether the call is currently on hold. This is an optional property and may be null if the hold status is unknown or not applicable. + /// + [JsonProperty("isOnHold", NullValueHandling = NullValueHandling.Ignore)] + public bool IsOnHold { get; set; } + + /// + /// The duration of the call, if available. This can be used to track how long the call has been active. This is an optional property and may be null if the duration is not available or applicable. + /// + [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 { - CallItem = item; + return !(Status == eCodecCallStatus.Disconnected + || Status == eCodecCallStatus.Disconnecting + || Status == eCodecCallStatus.Idle + || Status == eCodecCallStatus.Unknown); } } +} + +/// +/// Event args for when a call status changes, includes the call item with updated status and details. +/// +public class CodecCallStatusItemChangeEventArgs : EventArgs +{ + /// + /// The call item that has changed status, including its updated status and details. This property is read-only and is set through the constructor when the event args are created. + /// + public CodecActiveCallItem CallItem { get; private set; } + + /// + /// Constructor for CodecCallStatusItemChangeEventArgs + /// + /// The call item that has changed status. + public CodecCallStatusItemChangeEventArgs(CodecActiveCallItem item) + { + CallItem = item; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs b/src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs index 1445bd61..dddc7a6b 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs @@ -1,20 +1,20 @@ -namespace PepperDash.Essentials.Devices.Common.Codec + +namespace PepperDash.Essentials.Devices.Common.Codec; + +/// +/// Defines the contract for devices that have call hold functionality +/// +public interface IHasCallHold { /// - /// Defines the contract for IHasCallHold + /// Put the specified call on hold /// - public interface IHasCallHold - { - /// - /// Put the specified call on hold - /// - /// - void HoldCall(CodecActiveCallItem activeCall); + /// The call to put on hold + void HoldCall(CodecActiveCallItem activeCall); - /// - /// Resume the specified call - /// - /// - void ResumeCall(CodecActiveCallItem activeCall); - } + /// + /// Resume the specified call + /// + /// The call to resume + void ResumeCall(CodecActiveCallItem activeCall); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs b/src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs index c989e671..4cb46ec7 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs @@ -1,42 +1,41 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +/// +/// Describes a device that has Do Not Disturb mode capability +/// +public interface IHasDoNotDisturbMode { /// - /// Describes a device that has Do Not Disturb mode capability + /// Indictes whether Do Not Disturb mode is on (Activated) /// - 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(); - } + BoolFeedback DoNotDisturbModeIsOnFeedback { get; } /// - /// Defines the contract for devices that support Do Not Disturb mode with timeout functionality + /// Activates Do Not Disturb mode /// - public interface IHasDoNotDisturbModeWithTimeout : IHasDoNotDisturbMode - { - /// - /// Activates Do Not Disturb mode with a timeout - /// - /// - void ActivateDoNotDisturbMode(int timeout); - } -} \ No newline at end of file + 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); +} diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs b/src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs index 73884a2a..72742c2d 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs @@ -1,54 +1,54 @@ using System; using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +/// +/// Defines the contract for devices that support external source switching functionality +/// +public interface IHasExternalSourceSwitching { /// - /// Defines the contract for IHasExternalSourceSwitching + /// Gets a value indicating whether the external source list is enabled /// - public interface IHasExternalSourceSwitching - { - /// - /// Gets a value indicating whether the external source list is enabled - /// - bool ExternalSourceListEnabled { get; } + bool ExternalSourceListEnabled { get; } - /// - /// Gets the external source input port identifier - /// - string ExternalSourceInputPort { get; } + /// + /// Gets the port name for external source input switching + /// + 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); + /// + /// Adds an external source to the list of available sources for switching + /// + /// + /// + /// + /// + void AddExternalSource(string connectorId, string key, string name, eExternalSourceType type); - /// - /// Clears all external sources from the list - /// - void ClearExternalSources(); + /// + /// 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); - /// - /// Sets the selected source by its key - /// - /// The unique key of the source to select - void SetSelectedSource(string key); + /// + /// Clears all external sources from the list + /// + void ClearExternalSources(); - /// - /// Sets the action to run when routing between sources - /// - Action RunRouteAction { set; } - } + /// + /// Sets the selected external source for switching + /// + /// + void SetSelectedSource(string key); -} \ No newline at end of file + /// + /// Defines an action to run when an external source is selected for switching. + /// The action takes the key and name of the selected source as parameters. + /// + Action RunRouteAction { set; } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs index e10f61a3..89c852ca 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs @@ -1,57 +1,57 @@ -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +/// +/// Enumeration of eCodecCallDirection values +/// +public enum eCodecCallDirection { /// - /// Enumeration of eCodecCallDirection values + /// Unknown call direction /// - public enum eCodecCallDirection - { - /// - /// Unknown call direction - /// - Unknown = 0, - - /// - /// Incoming call direction - /// - Incoming, - - /// - /// Outgoing call direction - /// - Outgoing - } + Unknown = 0, /// - /// Represents a CodecCallDirection + /// Incoming call direction /// - 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; - } + 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; } } -} \ No newline at end of file + +} + diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs index 6116ab16..e9cc89d0 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs @@ -1,139 +1,138 @@ -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +/// +/// Enumeration of eCodecCallStatus values +/// +public enum eCodecCallStatus { /// - /// Enumeration of eCodecCallStatus values + /// Unknown call status /// - 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, - } - + Unknown = 0, /// - /// Represents a CodecCallStatus + /// Call is connected /// - public class CodecCallStatus + 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) { - - /// - /// Takes the Cisco call type and converts to the matching enum - /// - /// - /// - /// - /// ConvertToStatusEnum method - /// - public static eCodecCallStatus ConvertToStatusEnum(string s) + switch (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; - } - + 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; } } -} \ No newline at end of file +} + diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs index 2b9609fb..947d0ee2 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs @@ -1,76 +1,75 @@ -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +/// +/// Enumeration of eCodecCallType values +/// +public enum eCodecCallType { /// - /// Enumeration of eCodecCallType values + /// Unknown call type /// - 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 - } + Unknown = 0, /// - /// Represents a CodecCallType + /// Audio-only call type /// - public class CodecCallType + 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) { - - /// - /// Takes the Cisco call type and converts to the matching enum - /// - /// - /// - /// - /// ConvertToTypeEnum method - /// - public static eCodecCallType ConvertToTypeEnum(string s) + switch (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; - } - + case "Audio": + { + return eCodecCallType.Audio; + } + case "Video": + { + return eCodecCallType.Video; + } + case "AudioCanEscalate": + { + return eCodecCallType.AudioCanEscalate; + } + case "ForwardAllCall": + { + return eCodecCallType.ForwardAllCall; + } + default: + return eCodecCallType.Unknown; } } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs index 19a6d31b..b805b738 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs @@ -1,56 +1,55 @@ -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +/// +/// Enumeration of eMeetingPrivacy values +/// +public enum eMeetingPrivacy { /// - /// Enumeration of eMeetingPrivacy values + /// Unknown meeting privacy level /// - public enum eMeetingPrivacy - { - /// - /// Unknown meeting privacy level - /// - Unknown = 0, - - /// - /// Public meeting - /// - Public, - - /// - /// Private meeting - /// - Private - } + Unknown = 0, /// - /// Represents a CodecCallPrivacy + /// Public meeting /// - 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; - } + 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) + { + case "public": + { + return eMeetingPrivacy.Public; + } + case "private": + { + return eMeetingPrivacy.Private; + } + default: + return eMeetingPrivacy.Unknown; } } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs index eeab2801..0aa848a4 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs @@ -1,12 +1,11 @@ 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 - { +namespace PepperDash.Essentials.Devices.Common.Codec; + +/// +/// Defines minimum volume controls for a codec device with dialing capabilities +/// +public interface ICodecAudio : IBasicVolumeWithFeedback, IPrivacy +{ - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs index eeb6610f..b28b48cf 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs @@ -1,34 +1,34 @@ using System.Collections.Generic; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + + +/// +/// Defines the contract for IHasCallFavorites +/// +public interface IHasCallFavorites { /// - /// Defines the contract for IHasCallFavorites + /// Gets the call favorites for this device /// - public interface IHasCallFavorites - { - /// - /// Gets the call favorites for this device - /// - CodecCallFavorites CallFavorites { get; } - } + CodecCallFavorites CallFavorites { get; } +} + +/// +/// Represents a CodecCallFavorites +/// +public class CodecCallFavorites +{ + /// + /// Gets or sets the Favorites + /// + public List Favorites { get; set; } /// - /// Represents a CodecCallFavorites + /// Initializes a new instance of the CodecCallFavorites class /// - public class CodecCallFavorites + public CodecCallFavorites() { - /// - /// Gets or sets the Favorites - /// - public List Favorites { get; set; } - - /// - /// Initializes a new instance of the CodecCallFavorites class - /// - public CodecCallFavorites() - { - Favorites = new List(); - } + Favorites = new List(); } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs index 7f495daa..025e4a12 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs @@ -6,188 +6,131 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PepperDash.Essentials.Devices.Common.VideoCodec; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + + +public interface IHasCallHistory { + CodecCallHistory CallHistory { get; } + + void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry); +} + +public enum eCodecOccurrenceType +{ + Unknown = 0, + Placed = 1, + Received = 2, + NoAnswer = 3, +} + +/// +/// Represents the recent call history for a codec device +/// +public class CodecCallHistory +{ + public event EventHandler RecentCallsListHasChanged; + + public List RecentCalls { get; private set; } /// - /// Defines the contract for IHasCallHistory + /// Item that gets added to the list when there are no recent calls in history /// - public interface IHasCallHistory - { - /// - /// Gets the call history for this device - /// - CodecCallHistory CallHistory { get; } + CallHistoryEntry ListEmptyEntry; - /// - /// Removes the specified call history entry - /// - /// The call history entry to remove - void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry); + 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()); + } + } + + public void RemoveEntry(CallHistoryEntry entry) + { + RecentCalls.Remove(entry); + OnRecentCallsListChange(); } /// - /// Enumeration of eCodecOccurrenceType values + /// Generic call history entry, not device specific /// - public enum eCodecOccurrenceType + public class CallHistoryEntry : CodecActiveCallItem { - /// - /// Unknown occurrence type - /// - Unknown = 0, - - /// - /// Call was placed (outgoing) - /// - Placed = 1, - - /// - /// Call was received (incoming) - /// - Received = 2, - - /// - /// Call received no answer - /// - NoAnswer = 3, + [JsonConverter(typeof(IsoDateTimeConverter))] + [JsonProperty("startTime")] + public DateTime StartTime { get; set; } + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("occurrenceType")] + public eCodecOccurrenceType OccurrenceType { get; set; } + [JsonProperty("occurrenceHistoryId")] + public string OccurrenceHistoryId { get; set; } } /// - /// Represents a CodecCallHistory + /// Converts a list of call history entries returned by a Cisco codec to the generic list type /// - public class CodecCallHistory + /// + /// + public void ConvertCiscoCallHistoryToGeneric(List entries) { - /// - /// Event that is raised when the recent calls list has changed - /// - public event EventHandler RecentCallsListHasChanged; + var genericEntries = new List(); - /// - /// 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() + foreach (CiscoCallHistory.Entry entry in entries) { - ListEmptyEntry = new CallHistoryEntry() { Name = "No Recent Calls" }; - RecentCalls = new List(); - - RecentCalls.Add(ListEmptyEntry); - } - - void OnRecentCallsListChange() - { - var handler = RecentCallsListHasChanged; - if (handler != null) + genericEntries.Add(new CallHistoryEntry() { - handler(this, new EventArgs()); - } + Name = entry.DisplayName.Value, + Number = entry.CallbackNumber.Value, + StartTime = entry.LastOccurrenceStartTime.Value, + OccurrenceHistoryId = entry.LastOccurrenceHistoryId.Value, + OccurrenceType = ConvertToOccurenceTypeEnum(entry.OccurrenceType.Value) + }); } - /// - /// RemoveEntry method - /// - public void RemoveEntry(CallHistoryEntry entry) + // 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 + /// + /// + public eCodecOccurrenceType ConvertToOccurenceTypeEnum(string s) + { + switch (s) { - 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() + case "Placed": { - 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; - } - + return eCodecOccurrenceType.Placed; + } + case "Received": + { + return eCodecOccurrenceType.Received; + } + case "NoAnswer": + { + return eCodecOccurrenceType.NoAnswer; + } + default: + return eCodecOccurrenceType.Unknown; } } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs index 2dea5b4a..e70c1db6 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs @@ -1,37 +1,35 @@ using PepperDash.Essentials.Core; +namespace PepperDash.Essentials.Devices.Common.Codec; -namespace PepperDash.Essentials.Devices.Common.Codec + +/// +/// Defines the contract for IHasContentSharing +/// +public interface IHasContentSharing { /// - /// Defines the contract for IHasContentSharing + /// Gets feedback indicating whether content sharing is currently active /// - public interface IHasContentSharing - { - /// - /// Gets feedback indicating whether content sharing is currently active - /// - BoolFeedback SharingContentIsOnFeedback { get; } + BoolFeedback SharingContentIsOnFeedback { get; } - /// - /// Gets feedback about the current sharing source - /// - StringFeedback SharingSourceFeedback { 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; } + /// + /// Gets a value indicating whether content should be automatically shared while in a call + /// + bool AutoShareContentWhileInCall { get; } - /// - /// Starts content sharing - /// - void StartSharing(); + /// + /// Starts content sharing + /// + void StartSharing(); - /// - /// Stops content sharing - /// - void StopSharing(); - } - -} \ No newline at end of file + /// + /// Stops content sharing + /// + void StopSharing(); +} diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs index a5373004..f378e621 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs @@ -1,58 +1,57 @@ using System; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +/// +/// Requirements for a device that has dialing capabilities +/// +public interface IHasDialer { + // Add requirements for Dialer functionality + /// - /// Requirements for a device that has dialing capabilities + /// Event that is raised when call status changes /// - public interface IHasDialer - { - // Add requirements for Dialer functionality + event EventHandler CallStatusChange; - /// - /// Event that is raised when call status changes - /// - event EventHandler CallStatusChange; + /// + /// Dials the specified number + /// + /// The number to dial + void Dial(string number); - /// - /// 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 the specified active call - /// - /// The active call to end - void EndCall(CodecActiveCallItem activeCall); + /// + /// Ends all active calls + /// + void EndAllCalls(); - /// - /// Ends all active calls - /// - void EndAllCalls(); + /// + /// Accepts the specified incoming call + /// + /// The call item to accept + void AcceptCall(CodecActiveCallItem item); - /// - /// 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); - /// - /// 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); - /// - /// 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; } +} - /// - /// Gets a value indicating whether the device is currently in a call - /// - bool IsInCall { get; } - } - -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs b/src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs index 051f3b1a..3ea3ddde 100644 --- a/src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs @@ -4,153 +4,147 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -namespace PepperDash.Essentials.Devices.Common.DSP +namespace PepperDash.Essentials.Devices.Common.DSP; + +/// +/// Base class for DSP devices +/// +public abstract class DspBase : EssentialsDevice, ILevelControls { /// - /// Base class for DSP devices + /// Gets the collection of level control points /// - 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 + public Dictionary LevelControlPoints { get; private set; } /// - /// Base class for DSP control points + /// Gets the collection of dialer control points /// - public abstract class DspControlPoint : IKeyName + 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) { - /// - /// Gets or sets the Key - /// - public string Key { get; } - /// - /// Gets or sets the Name - /// - public string Name { get; private set; } + LevelControlPoints = new Dictionary(); + DialerControlPoints = new Dictionary(); + SwitcherControlPoints = new Dictionary(); + } - /// - /// Initializes a new instance of the DspControlPoint class - /// - /// The control point key - protected DspControlPoint(string key) => Key = key; + + // 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); } /// - /// Base class for DSP level control points with volume and mute functionality + /// Turns mute off /// - 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); - } - + public abstract void MuteOff(); /// - /// Base class for DSP dialer control points + /// Turns mute on /// - public abstract class DspDialerBase : DspControlPoint - { - /// - /// Initializes a new instance of the DspDialerBase class - /// - /// The dialer control point key - protected DspDialerBase(string key) : base(key) { } - } + 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 - -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs b/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs index 858cdf42..445cabcf 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs @@ -9,65 +9,66 @@ using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Displays +namespace PepperDash.Essentials.Devices.Common.Displays; + +/// +/// Represents a basic IR controlled display device. This class is intended to be used for simple displays that are controlled via IR and do not have a more robust API. It provides basic power and volume controls, as well as input switching via IR commands. +/// +public class BasicIrDisplay : DisplayBase, IBasicVolumeControls, IBridgeAdvanced { /// - /// Represents a BasicIrDisplay + /// Gets or sets the IrPort /// - public class BasicIrDisplay : DisplayBase, IBasicVolumeControls, IBridgeAdvanced + 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 { - /// - /// Gets or sets the IrPort - /// - public IrOutputPortController IrPort { get; private set; } - /// - /// Gets or sets the IrPulseTime - /// - public ushort IrPulseTime { get; set; } + get { return () => _PowerIsOn; } + } - /// - /// 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; } - } + /// + /// 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; + 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); + /// + /// 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); + 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 + InputPorts.AddRange(new RoutingPortCollection { new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Hdmi1), this, false), @@ -84,224 +85,223 @@ namespace PepperDash.Essentials.Devices.Common.Displays 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 + /// Hdmi1 method /// - public class BasicIrDisplayFactory : EssentialsDeviceFactory + public void Hdmi1() { - /// - /// 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; - } + 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); + } +} + +/// +/// Factory for creating BasicIrDisplay devices +/// +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; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs index 5db03a30..fba36564 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs @@ -13,426 +13,425 @@ using PepperDash.Essentials.Core.Routing; using Serilog.Events; using Feedback = PepperDash.Essentials.Core.Feedback; -namespace PepperDash.Essentials.Devices.Common.Displays +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; + /// - /// Abstract base class for display devices that provides common display functionality - /// including power control, input switching, and routing capabilities. + /// Gets or sets the current input port that is selected on the display. /// - public abstract class DisplayBase : EssentialsDevice, IDisplay, ICurrentSources, IHasFeedback + public RoutingInputPort CurrentInputPort { - private RoutingInputPort _currentInputPort; - - /// - /// Gets or sets the current input port that is selected on the display. - /// - public RoutingInputPort CurrentInputPort + get { - get - { - return _currentInputPort; - } - - protected set - { - if (_currentInputPort == value) return; - - _currentInputPort = value; - - InputChanged?.Invoke(this, _currentInputPort); - } + return _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 + protected set { - get - { - return _CurrentSourceInfo; - } - set - { - if (value == _CurrentSourceInfo) return; + if (_currentInputPort == value) return; - var handler = CurrentSourceChange; + _currentInputPort = value; - handler?.Invoke(_CurrentSourceInfo, ChangeType.WillChange); - - _CurrentSourceInfo = value; - - handler?.Invoke(_CurrentSourceInfo, ChangeType.DidChange); - } + InputChanged?.Invoke(this, _currentInputPort); } - SourceListItem _CurrentSourceInfo; + } - /// - public Dictionary CurrentSources { get; private set; } + /// + /// Event that is raised when the input changes on the display. + /// + public event InputChangedEventHandler InputChanged; - /// - public Dictionary CurrentSourceKeys { get; private set; } + /// + /// Event that is raised when the current source information changes. + /// + public event SourceInfoChangeHandler CurrentSourceChange; - /// - public event EventHandler CurrentSourcesChanged; + /// + /// Gets or sets the CurrentSourceInfoKey + /// + public string CurrentSourceInfoKey { get; set; } - /// - /// 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) + /// + /// Gets or sets the current source information for the display. + /// + public SourceListItem CurrentSourceInfo + { + get { - IsCoolingDownFeedback = new BoolFeedback("IsCoolingDown", IsCoolingDownFeedbackFunc); - IsWarmingUpFeedback = new BoolFeedback("IsWarmingUp", IsWarmingUpFeedbackFunc); + return _CurrentSourceInfo; + } + set + { + if (value == _CurrentSourceInfo) return; - Feedbacks.Add(IsCoolingDownFeedback); - Feedbacks.Add(IsWarmingUpFeedback); + var handler = CurrentSourceChange; - InputPorts = new RoutingPortCollection(); + handler?.Invoke(_CurrentSourceInfo, ChangeType.WillChange); - CurrentSources = new Dictionary + _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 + 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."); } - /// - /// Powers on the display device. Must be implemented by derived classes. - /// - public abstract void PowerOn(); + LinkDisplayToApi(displayDevice, trilist, joinMap); + } - /// - /// Powers off the display device. Must be implemented by derived classes. - /// - public abstract void PowerOff(); + /// + /// 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); - /// - /// Toggles the power state of the display device. Must be implemented by derived classes. - /// - public abstract void PowerToggle(); + trilist.StringInput[joinMap.Name.JoinNumber].StringValue = displayDevice.Name; - /// - /// 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) + if (displayDevice is ICommunicationMonitor commMonitor) { - 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); + commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); } - /// - /// 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) + // 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) { - this.LogDebug("Linking to Trilist {ipId}", trilist.ID.ToString("X")); - this.LogDebug("Linking to Display: {displayName}", displayDevice.Name); + trilist.SetBool(joinMap.IsTwoWayDisplay.JoinNumber, true); - trilist.StringInput[joinMap.Name.JoinNumber].StringValue = displayDevice.Name; + twoWayDisplay.CurrentInputFeedback.OutputChange += (o, a) => this.LogDebug("CurrentInputFeedback_OutputChange {input}", a.StringValue); - if (displayDevice is ICommunicationMonitor commMonitor) + inputNumberFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputSelect.JoinNumber]); + + twoWayDisplay.PowerIsOnFeedback.OutputChange += (o, a) => { - 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) { - if (!a.BoolValue) - { - inputNumber = 102; - inputNumberFeedback.FireUpdate(); + 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; + inputNumberFeedback.FireUpdate(); } + }; - // 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]); + twoWayDisplay.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff.JoinNumber]); + twoWayDisplay.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn.JoinNumber]); } - /// - public virtual void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem) + // Power Off + trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, () => { - 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; - } + inputNumber = 102; + inputNumberFeedback.FireUpdate(); + displayDevice.PowerOff(); + }); - 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) + // PowerOn + trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, () => { - if (CurrentSources.ContainsKey(signalType)) + inputNumber = 0; + inputNumberFeedback.FireUpdate(); + displayDevice.PowerOn(); + }); + + + for (int i = 0; i < displayDevice.InputPorts.Count; i++) + { + var localindex = i; + if (localindex >= joinMap.InputNamesOffset.JoinSpan) { - CurrentSources[signalType] = sourceListItem; + 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 { - CurrentSources.Add(signalType, sourceListItem); - } + inputKeys.Add(displayDevice.InputPorts[localindex].Key); - // Update the current source key for the specified signal type - if (CurrentSourceKeys.ContainsKey(signalType)) - { - CurrentSourceKeys[signalType] = sourceListKey; - } - else - { - CurrentSourceKeys.Add(signalType, sourceListKey); + 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]); } -} \ No newline at end of file + + /// + 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); + } + } + +} diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs b/src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs index b4314c6b..4d04fd28 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs @@ -1,89 +1,87 @@ using System; -namespace PepperDash.Essentials.Devices.Displays +namespace PepperDash.Essentials.Devices.Displays; + +/// +/// Defines the contract for IInputHdmi1 +/// +[Obsolete()] +public interface IInputHdmi1 { /// - /// Defines the contract for IInputHdmi1 + /// Switches to HDMI 1 input /// - [Obsolete()] - public interface IInputHdmi1 - { - /// - /// Switches to HDMI 1 input - /// - void InputHdmi1(); - } + void InputHdmi1(); +} +/// +/// Defines the contract for IInputHdmi2 +/// +[Obsolete()] +public interface IInputHdmi2 +{ /// - /// Defines the contract for IInputHdmi2 + /// Switches to HDMI 2 input /// - [Obsolete()] - public interface IInputHdmi2 - { - /// - /// Switches to HDMI 2 input - /// - void InputHdmi2(); - } + void InputHdmi2(); +} +/// +/// Defines the contract for IInputHdmi3 +/// +[Obsolete()] +public interface IInputHdmi3 +{ /// - /// Defines the contract for IInputHdmi3 + /// Switches to HDMI 3 input /// - [Obsolete()] - public interface IInputHdmi3 - { - /// - /// Switches to HDMI 3 input - /// - void InputHdmi3(); - } + void InputHdmi3(); +} +/// +/// Defines the contract for IInputHdmi4 +/// +[Obsolete()] +public interface IInputHdmi4 +{ /// - /// Defines the contract for IInputHdmi4 + /// Switches to HDMI 4 input /// - [Obsolete()] - public interface IInputHdmi4 - { - /// - /// Switches to HDMI 4 input - /// - void InputHdmi4(); - } + void InputHdmi4(); +} +/// +/// Defines the contract for IInputDisplayPort1 +/// +[Obsolete()] +public interface IInputDisplayPort1 +{ /// - /// Defines the contract for IInputDisplayPort1 + /// Switches to DisplayPort 1 input /// - [Obsolete()] - public interface IInputDisplayPort1 - { - /// - /// Switches to DisplayPort 1 input - /// - void InputDisplayPort1(); - } + void InputDisplayPort1(); +} +/// +/// Defines the contract for IInputDisplayPort2 +/// +[Obsolete()] +public interface IInputDisplayPort2 +{ /// - /// Defines the contract for IInputDisplayPort2 + /// Switches to DisplayPort 2 input /// - [Obsolete()] - public interface IInputDisplayPort2 - { - /// - /// Switches to DisplayPort 2 input - /// - void InputDisplayPort2(); - } + void InputDisplayPort2(); +} +/// +/// Defines the contract for IInputVga1 +/// +[Obsolete()] +public interface IInputVga1 +{ /// - /// Defines the contract for IInputVga1 + /// Switches to VGA 1 input /// - [Obsolete()] - public interface IInputVga1 - { - /// - /// Switches to VGA 1 input - /// - void InputVga1(); - } - -} \ No newline at end of file + void InputVga1(); +} diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs index 6f46b1a4..ead4c0eb 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs @@ -10,82 +10,62 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Displays +namespace PepperDash.Essentials.Devices.Common.Displays; + +/// +/// Represents a mock display device for testing and simulation purposes. +/// +public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs, IRoutingSinkWithSwitchingWithInputPort, IHasPowerControlWithFeedback { - /// - /// Represents a MockDisplay - /// - public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs, IRoutingSinkWithSwitchingWithInputPort, IHasPowerControlWithFeedback + public ISelectableItems Inputs { get; private set; } + + bool _PowerIsOn; + bool _IsWarmingUp; + bool _IsCoolingDown; + + protected override Func PowerIsOnFeedbackFunc { - /// - /// 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 { - get - { - return () => - { - return _PowerIsOn; - }; - } - } - /// - /// Gets the is cooling down feedback function - /// - protected override Func IsCoolingDownFeedbackFunc - { - get - { - return () => + return () => { - return _IsCoolingDown; + return _PowerIsOn; }; - } } - /// - /// Gets the is warming up feedback function - /// - protected override Func IsWarmingUpFeedbackFunc + } + protected override Func IsCoolingDownFeedbackFunc + { + get { - get + return () => { - return () => - { - return _IsWarmingUp; - }; - } + return _IsCoolingDown; + }; } - /// - /// 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) + } + protected override Func IsWarmingUpFeedbackFunc + { + get { - Inputs = new MockDisplayInputs + return () => { - Items = new Dictionary + return _IsWarmingUp; + }; + } + } + protected override Func CurrentInputFeedbackFunc { get { return () => Inputs.CurrentItem; } } + + int VolumeHeldRepeatInterval = 200; + ushort VolumeInterval = 655; + ushort _FakeVolumeLevel = 31768; + bool _IsMuted; + + 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 ) }, @@ -93,276 +73,239 @@ namespace PepperDash.Essentials.Devices.Common.Displays { "HDMI4", new MockDisplayInput ("HDMI4", "HDMI 4",this )}, { "DP", new MockDisplayInput ("DP", "DisplayPort", this ) } } - }; + }; - Inputs.CurrentItemChanged += (o, a) => CurrentInputFeedback.FireUpdate(); + Inputs.CurrentItemChanged += (o, a) => CurrentInputFeedback.FireUpdate(); - var hdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo, + 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 { } + 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 }); - if (currentInput != null) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "SetInput: {0}", selector); - currentInput.IsSelected = false; - } + VolumeLevelFeedback = new IntFeedback("volume", () => { return _FakeVolumeLevel; }); + MuteFeedback = new BoolFeedback("muteOn", () => _IsMuted); - 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); - } + WarmupTime = 10000; + CooldownTime = 10000; } /// - /// Represents a MockDisplayFactory + /// PowerOn method /// - public class MockDisplayFactory : EssentialsDeviceFactory + /// + public override void PowerOn() { - /// - /// Initializes a new instance of the MockDisplayFactory class - /// - public MockDisplayFactory() + if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) { - 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); + _IsWarmingUp = true; + IsWarmingUpFeedback.InvokeFireUpdate(); + // Fake power-up cycle + WarmupTimer = new CTimer(o => + { + _IsWarmingUp = false; + _PowerIsOn = true; + IsWarmingUpFeedback.InvokeFireUpdate(); + PowerIsOnFeedback.InvokeFireUpdate(); + }, WarmupTime); } } -} \ No newline at end of file + + 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); + } + } + + public override void PowerToggle() + { + if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue) + PowerOff(); + else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue) + PowerOn(); + } + + 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); + } + } + + public void SetInput(string selector) + { + ISelectableItem currentInput = null; + + + 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 + + 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 + + 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); + } + //} + } + + 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 + + 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" }; + } + + 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); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs index b30963ac..77155a67 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs @@ -2,135 +2,95 @@ using System.Collections.Generic; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -namespace PepperDash.Essentials.Devices.Common.Displays +namespace PepperDash.Essentials.Devices.Common.Displays; + +public class MockDisplayInputs : ISelectableItems { - /// - /// Represents a MockDisplayInputs - /// - public class MockDisplayInputs : ISelectableItems + private Dictionary _items; + + public Dictionary Items { - private Dictionary _items; - - /// - /// Gets or sets the collection of selectable items - /// - public Dictionary Items + get { - get - { - return _items; - } - set - { - if (_items == value) - return; - - _items = value; - - ItemsUpdated?.Invoke(this, null); - } + return _items; } - - private string _currentItem; - - /// - /// Gets or sets the currently selected item - /// - public string CurrentItem + set { - get - { - return _currentItem; - } - set - { - if (_currentItem == value) - return; + if (_items == value) + return; - _currentItem = value; + _items = value; - CurrentItemChanged?.Invoke(this, null); - } + ItemsUpdated?.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 string _currentItem; + + public string CurrentItem + { + get + { + return _currentItem; + } + set + { + if (_currentItem == value) + return; + + _currentItem = value; + + CurrentItemChanged?.Invoke(this, null); + } + } + + public event EventHandler ItemsUpdated; + public event EventHandler CurrentItemChanged; +} + +public class MockDisplayInput : ISelectableItem +{ + private MockDisplay _parent; + + private bool _isSelected; + + public bool IsSelected { - private MockDisplay _parent; - - private bool _isSelected; - - /// - /// Gets or sets a value indicating whether this input is selected - /// - public bool IsSelected + get { - get - { - return _isSelected; - } - set - { - if (_isSelected == value) - return; - - _isSelected = value; - - ItemUpdated?.Invoke(this, null); - } + return _isSelected; } - - /// - /// 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) + set { - Key = key; - Name = name; - _parent = parent; + if (_isSelected == value) + return; + + _isSelected = value; + + ItemUpdated?.Invoke(this, null); } + } - /// - /// Select method - /// - public void Select() + public string Name { get; set; } + + public string Key { get; set; } + + public event EventHandler ItemUpdated; + + public MockDisplayInput(string key, string name, MockDisplay parent) + { + Key = key; + Name = name; + _parent = parent; + } + + public void Select() + { + if (!_parent.PowerIsOnFeedback.BoolValue) _parent.PowerOn(); + + foreach(var input in _parent.Inputs.Items) { - if (!_parent.PowerIsOnFeedback.BoolValue) _parent.PowerOn(); - - foreach (var input in _parent.Inputs.Items) - { - input.Value.IsSelected = input.Key == this.Key; - } + input.Value.IsSelected = input.Key == this.Key; } } } diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs index 80c1f8ee..7f7779c5 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs @@ -434,7 +434,7 @@ namespace PepperDash.Essentials.Devices.Common.Shades /// /// Factory for ScreenLiftController devices /// - public class ScreenLiftControllerFactory : EssentialsDeviceFactory + public class ScreenLiftControllerFactory : EssentialsDeviceFactory { /// /// Constructor for ScreenLiftControllerFactory @@ -453,4 +453,4 @@ namespace PepperDash.Essentials.Devices.Common.Shades return new ScreenLiftController(dc.Key, dc.Name, props); } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs index 64617770..cdf214bf 100644 --- a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs +++ b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs @@ -7,152 +7,154 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Routing; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Generic +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; + /// - /// Represents a GenericSink + /// Initializes a new instance of the GenericSink class /// - public class GenericSink : EssentialsDevice, IRoutingSinkWithSwitchingWithInputPort, ICurrentSources + /// The device key + /// The device name + public GenericSink(string key, string name) : base(key, name) { - /// - public Dictionary CurrentSources { get; private set; } + InputPorts = new RoutingPortCollection(); - /// - public Dictionary CurrentSourceKeys { get; private set; } + var inputPort = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo | eRoutingSignalType.SecondaryAudio, eRoutingPortConnectionType.Hdmi, null, this); - /// - public event EventHandler CurrentSourcesChanged; + InputPorts.Add(inputPort); - /// - /// 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 + CurrentSources = new Dictionary { { eRoutingSignalType.Audio, null }, { eRoutingSignalType.Video, null }, }; - CurrentSourceKeys = new Dictionary + CurrentSourceKeys = new Dictionary { { eRoutingSignalType.Audio, string.Empty }, { eRoutingSignalType.Video, string.Empty }, }; - } + } - /// - public void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem) + /// + public void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem) + { + foreach (eRoutingSignalType type in Enum.GetValues(typeof(eRoutingSignalType))) { - 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) { - 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); - } + this.LogDebug("Skipping {type}", type); + continue; } - // Raise the CurrentSourcesChanged event - CurrentSourcesChanged?.Invoke(this, EventArgs.Empty); - } - private void UpdateCurrentSources(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem) - { - CurrentSources[signalType] = sourceListItem; - CurrentSourceKeys[signalType] = sourceListKey; - } + this.LogDebug("setting {type}", type); - /// - /// 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 (signalType.HasFlag(type)) { - if (value == _currentSource) - { - return; - } - - CurrentSourceChange?.Invoke(_currentSource, ChangeType.WillChange); - - _currentSource = value; - - CurrentSourceChange?.Invoke(_currentSource, ChangeType.DidChange); + UpdateCurrentSources(type, sourceListKey, sourceListItem); } } + // Raise the CurrentSourcesChanged event + CurrentSourcesChanged?.Invoke(this, EventArgs.Empty); + } - /// - /// Gets the current input port - /// - public RoutingInputPort CurrentInputPort => InputPorts[0]; + private void UpdateCurrentSources(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem) + { + CurrentSources[signalType] = sourceListItem; + CurrentSourceKeys[signalType] = sourceListKey; + } - /// - /// Event fired when the current source changes - /// - public event SourceInfoChangeHandler CurrentSourceChange; + /// + /// Gets or sets the InputPorts + /// + public RoutingPortCollection InputPorts { get; private set; } - /// - public event InputChangedEventHandler InputChanged; + /// + /// Gets or sets the CurrentSourceInfoKey + /// + public string CurrentSourceInfoKey { get; set; } - /// - public void ExecuteSwitch(object inputSelector) + private SourceListItem _currentSource; + /// + /// Gets or sets the CurrentSourceInfo + /// + public SourceListItem CurrentSourceInfo + { + get => _currentSource; + set { - this.LogDebug("GenericSink Executing Switch to: {inputSelector}", inputSelector); + if (value == _currentSource) + { + return; + } + + CurrentSourceChange?.Invoke(_currentSource, ChangeType.WillChange); + + _currentSource = value; + + CurrentSourceChange?.Invoke(_currentSource, ChangeType.DidChange); } } /// - /// Represents a GenericSinkFactory + /// Gets the current input port /// - public class GenericSinkFactory : EssentialsDeviceFactory - { - /// - /// Initializes a new instance of the GenericSinkFactory class - /// - public GenericSinkFactory() - { - TypeNames = new List() { "genericsink", "genericdestination" }; - } + public RoutingInputPort CurrentInputPort => InputPorts[0]; - /// - /// 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); - } + /// + /// 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); + } +} + + + diff --git a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs index 3d0f1304..9926f31b 100644 --- a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs +++ b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs @@ -5,77 +5,76 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common +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 { /// - /// Represents a GenericSource + /// Initializes a new instance of the GenericSourceFactory class /// - public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingSource, IUsageTracking + public GenericSourceFactory() { - - /// - /// 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 + TypeNames = new List() { "genericsource" }; } /// - /// Represents a GenericSourceFactory + /// BuildDevice method /// - public class GenericSourceFactory : EssentialsDeviceFactory + /// + public override EssentialsDevice BuildDevice(DeviceConfig dc) { - /// - /// 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); - } + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Source Device"); + return new GenericSource(dc.Key, dc.Name); } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs b/src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs index 9dd3b816..a77b936b 100644 --- a/src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs @@ -1,6 +1,4 @@ - - -using System; +using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharpPro.DeviceSupport; @@ -11,167 +9,167 @@ using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Lighting; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Lighting +namespace PepperDash.Essentials.Devices.Common.Lighting; + + +/// +/// Base class for lighting devices that support scenes +/// +public abstract class LightingBase : EssentialsBridgeableDevice, ILightingScenes { + #region ILightingScenes Members + /// - /// Base class for lighting devices that support scenes + /// Event fired when lighting scene changes /// - public abstract class LightingBase : EssentialsBridgeableDevice, ILightingScenes + 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) { - #region ILightingScenes Members + LightingScenes = new List(); - /// - /// Event fired when lighting scene changes - /// - public event EventHandler LightingSceneChange; + CurrentLightingScene = new LightingScene(); + //CurrentLightingSceneFeedback = new IntFeedback(() => { return int.Parse(this.CurrentLightingScene.ID); }); + } - /// - /// Gets or sets the LightingScenes - /// - public List LightingScenes { get; protected set; } + /// + /// Selects the specified lighting scene + /// + /// The lighting scene to select + public abstract void SelectScene(LightingScene scene); - /// - /// Gets or sets the CurrentLightingScene - /// - public LightingScene CurrentLightingScene { get; protected set; } + /// + /// SimulateSceneSelect method + /// + public void SimulateSceneSelect(string sceneName) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Simulating selection of scene '{0}'", sceneName); - /// - /// Gets or sets the CurrentLightingSceneFeedback - /// - public IntFeedback CurrentLightingSceneFeedback { get; protected set; } + var scene = LightingScenes.FirstOrDefault(s => s.Name.Equals(sceneName)); - #endregion - - /// - /// Initializes a new instance of the LightingBase class - /// - /// The device key - /// The device name - protected LightingBase(string key, string name) - : base(key, name) + if (scene != null) { - LightingScenes = new List(); - - CurrentLightingScene = new LightingScene(); - //CurrentLightingSceneFeedback = new IntFeedback(() => { return int.Parse(this.CurrentLightingScene.ID); }); + CurrentLightingScene = scene; + OnLightingSceneChange(); } + } - /// - /// Selects the specified lighting scene - /// - /// The lighting scene to select - public abstract void SelectScene(LightingScene scene); - - /// - /// SimulateSceneSelect method - /// - public void SimulateSceneSelect(string sceneName) + /// + /// Sets the IsActive property on each scene and fires the LightingSceneChange event + /// + protected void OnLightingSceneChange() + { + foreach (var scene in LightingScenes) { - Debug.LogMessage(LogEventLevel.Debug, this, "Simulating selection of scene '{0}'", sceneName); + if (scene == CurrentLightingScene) + scene.IsActive = true; - 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."); - } + scene.IsActive = false; + } + LightingSceneChange?.Invoke(this, new LightingSceneChangeEventArgs(CurrentLightingScene)); + } - return LinkLightingToApi(lightingDevice, trilist, joinMap); + /// + /// 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."); } - /// - /// 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) + 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) { - Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + var index = sceneIndex; - Debug.LogMessage(LogEventLevel.Information, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString()); + 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; - // GenericLighitng Actions & FeedBack - trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u])); + sceneIndex++; + } - var sceneIndex = 0; + trilist.OnlineStatusChange += (sender, args) => + { + if (!args.DeviceOnLine) return; + + 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; + scene.IsActiveFeedback.FireUpdate(); 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; - } + return joinMap; } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs index ecce473e..6a1a816d 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs @@ -1,28 +1,27 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Room.Config; -namespace PepperDash.Essentials.Devices.Common.Room +namespace PepperDash.Essentials.Devices.Common.Room; + +/// +/// Defines the contract for IEssentialsHuddleSpaceRoom +/// +public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IHasDefaultDisplay, IHasCurrentVolumeControls, IRoomOccupancy, + IEmergency, IMicrophonePrivacy { /// - /// Defines the contract for IEssentialsHuddleSpaceRoom + /// Gets whether to exclude this room from global functions /// - public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IHasDefaultDisplay, IHasCurrentVolumeControls, IRoomOccupancy, - IEmergency, IMicrophonePrivacy - { - /// - /// Gets whether to exclude this room from global functions - /// - bool ExcludeFromGlobalFunctions { get; } + bool ExcludeFromGlobalFunctions { get; } - /// - /// Runs the route action for the given routeKey and sourceListKey - /// - /// The route key - void RunRouteAction(string routeKey); + /// + /// Runs the route action for the given routeKey and sourceListKey + /// + /// The route key + void RunRouteAction(string routeKey); - /// - /// Gets the PropertiesConfig - /// - EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; } - } -} \ No newline at end of file + /// + /// Gets the PropertiesConfig + /// + EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs index 5547f595..728e1e1b 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs @@ -1,51 +1,53 @@ -using PepperDash.Essentials.Core; +using System; +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 +namespace PepperDash.Essentials.Devices.Common.Room; + + +/// +/// Defines the contract for IEssentialsHuddleVtc1Room +/// +[Obsolete("Obsolete in favor of IEssentialsRoom. This interface will be removed in a future release.")] +public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback, + IRoomOccupancy, IEmergency, IMicrophonePrivacy { /// - /// Defines the contract for IEssentialsHuddleVtc1Room + /// Gets the PropertiesConfig /// - public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback, - IRoomOccupancy, IEmergency, IMicrophonePrivacy - { - /// - /// Gets the PropertiesConfig - /// - EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; } + EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; } - /// - /// Gets whether to exclude this room from global functions - /// - bool ExcludeFromGlobalFunctions { 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); + /// + /// 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 ScheduleSource + /// + IHasScheduleAwareness ScheduleSource { get; } - /// - /// Gets the InCallFeedback - /// - new BoolFeedback InCallFeedback { get; } + /// + /// Gets the InCallFeedback + /// + new BoolFeedback InCallFeedback { get; } - /// - /// Gets the PrivacyModeIsOnFeedback - /// - new BoolFeedback PrivacyModeIsOnFeedback { get; } + /// + /// Gets the PrivacyModeIsOnFeedback + /// + new BoolFeedback PrivacyModeIsOnFeedback { get; } - /// - /// Gets the DefaultCodecRouteString - /// - string DefaultCodecRouteString { get; } - } -} \ No newline at end of file + /// + /// Gets the DefaultCodecRouteString + /// + string DefaultCodecRouteString { get; } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs index e45be6e0..7b6db77e 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs @@ -1,15 +1,16 @@ using PepperDash.Essentials.Room.Config; -namespace PepperDash.Essentials.Devices.Common.Room +namespace PepperDash.Essentials.Devices.Common.Room; + + +/// +/// Defines the contract for IEssentialsRoomPropertiesConfig +/// +public interface IEssentialsRoomPropertiesConfig { /// - /// Defines the contract for IEssentialsRoomPropertiesConfig + /// Gets the PropertiesConfig /// - public interface IEssentialsRoomPropertiesConfig - { - /// - /// Gets the PropertiesConfig - /// - EssentialsRoomPropertiesConfig PropertiesConfig { get; } - } + EssentialsRoomPropertiesConfig PropertiesConfig { get; } } + diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs index 9301f37d..2dd79a99 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs @@ -5,37 +5,36 @@ using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Devices.Common.Displays; using PepperDash.Essentials.Room.Config; +namespace PepperDash.Essentials.Devices.Common.Room; -namespace PepperDash.Essentials.Devices.Common.Room +/// +/// Defines the contract for IEssentialsTechRoom +/// +public interface IEssentialsTechRoom : IEssentialsRoom, ITvPresetsProvider, IBridgeAdvanced, IRunDirectRouteAction { /// - /// Defines the contract for IEssentialsTechRoom + /// Gets the PropertiesConfig /// - public interface IEssentialsTechRoom : IEssentialsRoom, ITvPresetsProvider, IBridgeAdvanced, IRunDirectRouteAction - { - /// - /// Gets the PropertiesConfig - /// - EssentialsTechRoomConfig PropertiesConfig { get; } + EssentialsTechRoomConfig PropertiesConfig { get; } - /// - /// Gets the Tuners - /// - Dictionary Tuners { get; } + /// + /// Gets the Tuners + /// + Dictionary Tuners { get; } - /// - /// Gets the Displays - /// - Dictionary Displays { get; } + /// + /// Gets the Displays + /// + Dictionary Displays { get; } - /// - /// Powers on the room - /// - void RoomPowerOn(); + /// + /// Powers on the room + /// + void RoomPowerOn(); - /// - /// Powers off the room - /// - void RoomPowerOff(); - } + /// + /// Powers off the room + /// + void RoomPowerOff(); } + diff --git a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs index 7d49b9b7..6171ef86 100644 --- a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs @@ -656,5 +656,5 @@ namespace PepperDash.Essentials.Devices.Common } } } +} -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs b/src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs index 193b41e7..94c5dd51 100644 --- a/src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs @@ -1,36 +1,35 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Devices.Common +namespace PepperDash.Essentials.Devices.Common; + +/// +/// Represents a SetTopBoxPropertiesConfig +/// +public class SetTopBoxPropertiesConfig : PepperDash.Essentials.Core.Config.SourceDevicePropertiesConfigBase { /// - /// Represents a SetTopBoxPropertiesConfig + /// Gets or sets the HasPresets /// - 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; } + 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; } - } -} \ No newline at end of file + /// + /// Gets or sets the Control + /// + public ControlPropertiesConfig Control { get; set; } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs b/src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs index e0080627..c1e613e2 100644 --- a/src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs +++ b/src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs @@ -7,181 +7,169 @@ using PepperDash.Essentials.Core.CrestronIO; using PepperDash.Essentials.Core.Shades; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Shades +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 the label for the stop or preset button, depending on how the shade is configured + /// + public string StopOrPresetButtonLabel { get; set; } + + /// + /// Constructor for RelayControlledShade + /// + /// + /// + /// + public RelayControlledShade(string key, string name, RelayControlledShadeConfigProperties config) + : base(key, name) + { + Config = config; + + RelayPulseTime = Config.RelayPulseTime; + + StopOrPresetButtonLabel = Config.StopOrPresetLabel; + + } + + /// + 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(); + } + + /// + public override void Open() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Opening Shade: '{0}'", this.Name); + + PulseOutput(OpenRelay, RelayPulseTime); + } + + /// + + public override void Stop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Shade: '{0}'", this.Name); + + PulseOutput(StopOrPresetRelay, RelayPulseTime); + } + + /// + 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 the 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; + } + } + +} + +/// +/// Configuration properties for RelayControlledShade +/// +public class RelayControlledShadeConfigProperties { /// - /// Controls a single shade using three relays + /// The amount of time in milliseconds to pulse the relay for when opening or closing the shade /// - 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; - } - } - - } + public int RelayPulseTime { get; set; } /// - /// Represents a RelayControlledShadeConfigProperties + /// The relays that control the shade /// - 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; } - } - } + public ShadeRelaysConfig Relays { get; set; } /// - /// Represents a RelayControlledShadeFactory + /// The label for the stop or preset button, depending on how the shade is configured /// - public class RelayControlledShadeFactory : EssentialsDeviceFactory + public string StopOrPresetLabel { get; set; } + + /// + /// Configuration for the relays that control the shade + /// + public class ShadeRelaysConfig { /// - /// Initializes a new instance of the RelayControlledShadeFactory class + /// The relay that opens the shade /// - public RelayControlledShadeFactory() - { - TypeNames = new List() { "relaycontrolledshade" }; - } + public IOPortConfig Open { get; set; } /// - /// BuildDevice method + /// The relay that stops the shade or presets the shade to a certain position, depending on how the shade is configured /// - /// - 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()); + public IOPortConfig StopOrPreset { get; set; } - return new RelayControlledShade(dc.Key, dc.Name, props); - } + /// + /// The relay that closes the shade + /// + public IOPortConfig Close { get; set; } + } +} + +/// +/// Factory for creating RelayControlledShade devices +/// +public class RelayControlledShadeFactory : EssentialsDeviceFactory +{ + /// + /// Constructor for RelayControlledShadeFactory + /// + public RelayControlledShadeFactory() + { + TypeNames = new List() { "relaycontrolledshade" }; } + /// + 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); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs b/src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs index ba3d67dd..6b8e13b8 100644 --- a/src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs @@ -1,39 +1,40 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Shades; -namespace PepperDash.Essentials.Devices.Common.Shades +namespace PepperDash.Essentials.Devices.Common.Shades; + + +/// +/// Base class for shade devices +/// +public abstract class ShadeBase : EssentialsDevice, IShadesOpenCloseStop { /// - /// Base class for shade devices + /// Initializes a new instance of the ShadeBase class /// - public abstract class ShadeBase : EssentialsDevice, IShadesOpenCloseStop + /// The device key + /// The device name + public ShadeBase(string key, string name) + : base(key, name) { - /// - /// 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 } + + #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 } + diff --git a/src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs b/src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs index dc8cb125..7d22ec56 100644 --- a/src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs +++ b/src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs @@ -5,105 +5,96 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Shades; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Shades +namespace PepperDash.Essentials.Devices.Common.Shades; + +/// +/// Class that contains the shades to be controlled in a room +/// +public class ShadeController : EssentialsDevice, IShades +{ + ShadeControllerConfigProperties Config; + + /// + /// List of shades to be controlled by this controller + /// + public List Shades { get; private set; } + + /// + /// Constructor for ShadeController + /// + /// + /// + /// + public ShadeController(string key, string name, ShadeControllerConfigProperties config) + : base(key, name) + { + Config = config; + + Shades = new List(); + } + + /// + 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); + } +} + +/// +/// Class representing the properties for the ShadeController device, including a list of shades to control +/// +public class ShadeControllerConfigProperties { /// - /// Class that contains the shades to be controlled in a room + /// List of shades to control, represented by their unique keys /// - 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); - } - } + public List Shades { get; set; } /// - /// Represents a ShadeControllerConfigProperties + /// Class representing the configuration for an individual shade, including its unique key /// - public class ShadeControllerConfigProperties + public class ShadeConfig : IKeyed { /// - /// Gets or sets the Shades + /// The unique key of the shade device to be controlled /// - public List Shades { get; set; } - - - /// - /// Represents a ShadeConfig - /// - public class ShadeConfig - { - /// - /// Gets or sets the Key - /// - public string Key { get; set; } - } + public string Key { get; set; } } +} +/// +/// Factory for creating ShadeController devices +/// +public class ShadeControllerFactory : EssentialsDeviceFactory +{ /// - /// Represents a ShadeControllerFactory + /// Constructor for ShadeControllerFactory /// - public class ShadeControllerFactory : EssentialsDeviceFactory + public ShadeControllerFactory() { - /// - /// 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); - } + TypeNames = new List() { "shadecontroller" }; } + /// + 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); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs index afe47814..9483a6c5 100644 --- a/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs @@ -1,6 +1,6 @@ using System; +using System.Collections.Generic; using Crestron.SimplSharp; - using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; @@ -8,188 +8,157 @@ using PepperDash.Essentials.Devices.Common.Sources; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.SoftCodec +namespace PepperDash.Essentials.Devices.Common.SoftCodec; + +public class BlueJeansPc : InRoomPc, IRunRouteAction, IRoutingSink { - /// - /// Represents a BlueJeansPc - /// - public class BlueJeansPc : InRoomPc, IRunRouteAction, IRoutingSink + + public RoutingInputPort AnyVideoIn { get; private set; } + + public RoutingInputPort CurrentInputPort => AnyVideoIn; + + #region IRoutingInputs Members + + public RoutingPortCollection InputPorts { get; private set; } + + #endregion + + public BlueJeansPc(string key, string name) + : base(key, name) { - - /// - /// 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 { - 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 + (AnyVideoIn = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.None, 0, this)) + }; } -} \ No newline at end of file + #region IRunRouteAction Members + + public void RunRouteAction(string routeKey, string sourceListKey) + { + RunRouteAction(routeKey, sourceListKey, null); + } + + 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 + + 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; + + public event SourceInfoChangeHandler CurrentSourceChange; + + #endregion +} diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs index f8a8f640..942832f3 100644 --- a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs @@ -3,132 +3,130 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.SoftCodec +namespace PepperDash.Essentials.Devices.Common.SoftCodec; + + +/// +/// Represents a GenericSoftCodec +/// +public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingSinkWithSwitchingWithInputPort { + private RoutingInputPort _currentInputPort; + /// - /// Represents a GenericSoftCodec + /// Gets or sets the CurrentInputPort /// - public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingSinkWithSwitchingWithInputPort + public RoutingInputPort CurrentInputPort { - private RoutingInputPort _currentInputPort; - - /// - /// Gets or sets the CurrentInputPort - /// - public RoutingInputPort CurrentInputPort + get => _currentInputPort; + set { - get => _currentInputPort; - set - { - _currentInputPort = value; + _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; + 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) + { + 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; + } } + diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs index e2ef1c09..d12dd37a 100644 --- a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs +++ b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs @@ -1,83 +1,64 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.Sources +namespace PepperDash.Essentials.Devices.Common.Sources; + +public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking { + public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } + public string IconName { get; set; } + public BoolFeedback HasPowerOnFeedback { get; private set; } + /// - /// Represents a InRoomPc + /// Gets or sets the AnyVideoOut /// - public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking + 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) { - /// - /// 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; } + IconName = "PC"; + HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback", + () => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus); - /// - /// 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 + 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 } -} \ No newline at end of file + /// + /// Passes through the VideoStatuses list + /// + public FeedbackCollection Feedbacks + { + get + { + var newList = new FeedbackCollection(); + newList.AddRange(this.GetVideoStatuses().ToList()); + return newList; + } + } + + + #region IUsageTracking Members + + public UsageTracking UsageTracker { get; set; } + + #endregion +} + diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs b/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs index 83ccfc4c..0a7466e7 100644 --- a/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs +++ b/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs @@ -1,83 +1,68 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.Sources +namespace PepperDash.Essentials.Devices.Common.Sources; + +public class Laptop : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking { + public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } + public string IconName { get; set; } + public BoolFeedback HasPowerOnFeedback { get; private set; } + /// - /// Represents a Laptop + /// Gets or sets the AnyVideoOut /// - public class Laptop : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking + 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) { - /// - /// 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; } + IconName = "Laptop"; - /// - /// Gets or sets the AnyVideoOut - /// - public RoutingOutputPort AnyVideoOut { get; private set; } + HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback", + () => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus); - #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) + OutputPorts = new RoutingPortCollection { - 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 + (AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, + eRoutingPortConnectionType.None, 0, this)) + }; } -} \ No newline at end of file + + #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 + + public UsageTracking UsageTracker { get; set; } + + #endregion +} + diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs index 6cf11c54..453b6aa0 100644 --- a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs @@ -7,244 +7,244 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common +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 { /// - /// Represents a AppleTV - /// Wrapper class for an IR-Controlled AppleTV + /// Gets or sets the IrPort /// - [Description("Wrapper class for an IR-Controlled AppleTV")] - public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource, IRoutingOutputs + 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) { - /// - /// Gets or sets the IrPort - /// - public IrOutputPortController IrPort { get; private set; } + IrPort = portCont; + DeviceManager.AddDevice(portCont); - /// - /// 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; } } + 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 }; - /// - /// 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) + 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()) { - 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); + Debug.LogMessage(LogEventLevel.Verbose, this, "Expected IR Function Name: {0}", value); } } -} \ No newline at end of file + + + #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); + } +} + diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs index 8872172a..8f4f1b5b 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs @@ -1,220 +1,220 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + + +/// +/// Represents a CiscoCallHistory +/// +public class CiscoCallHistory { /// - /// Represents a CiscoCallHistory + /// Represents a CallbackNumber /// - public class CiscoCallHistory + public class CallbackNumber { /// - /// Represents a CallbackNumber + /// Gets or sets the Value /// - 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; } - } + public string Value { get; set; } } -} \ No newline at end of file + + /// + /// 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; } + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs index e6e2be7e..333c4aa9 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs @@ -3,84 +3,83 @@ using System.Collections.Generic; using System.Linq; using PepperDash.Essentials.Core.Presets; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + +/// +/// Interface for camera presets +/// +public interface IHasCodecRoomPresets { /// - /// Interface for camera presets + /// Event that is raised when the list of room presets has changed. /// - 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); - } + event EventHandler CodecRoomPresetsListHasChanged; /// - /// Static class for converting non-generic RoomPresets to generic CameraPresets. + /// List of near end presets that can be recalled. /// - 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(); - } - } + List NearEndPresets { get; } /// - /// Represents a CodecRoomPreset + /// List of far end presets that can be recalled. /// - public class CodecRoomPreset : PresetBase - { - /// - /// - /// - /// - /// - /// - /// - public CodecRoomPreset(int id, string description, bool def, bool isDef) - : base(id, description, def, isDef) - { + 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 room preset on a video codec. Typically stores camera position(s) and video routing. Can be recalled by Far End if enabled. +/// +public class CodecRoomPreset : PresetBase +{ + /// + /// + /// + /// + /// + /// + /// + public CodecRoomPreset(int id, string description, bool def, bool isDef) + : base(id, description, def, isDef) + { - } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eCommandType.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eCommandType.cs index b68f280d..d33ec5c5 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eCommandType.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eCommandType.cs @@ -1,4 +1,3 @@ -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco -{ - enum eCommandType { SessionStart, SessionEnd, Command, GetStatus, GetConfiguration }; -} \ No newline at end of file +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco; + +enum eCommandType { SessionStart, SessionEnd, Command, GetStatus, GetConfiguration }; \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs index 6d77551d..446e4138 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs @@ -22,4 +22,4 @@ /// Error } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs index 6d5811e3..bfee4fed 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs @@ -34,4 +34,4 @@ /// other } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs index e75f436d..7298cfe7 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs @@ -1,16 +1,16 @@ using PepperDash.Essentials.Core.Presets; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + + +/// +/// Base class for presets that can be converted to PresetBase +/// +public abstract class ConvertiblePreset { /// - /// Base class for presets that can be converted to PresetBase + /// Converts the preset to a PresetBase /// - public abstract class ConvertiblePreset - { - /// - /// Converts the preset to a PresetBase - /// - /// - public abstract PresetBase ConvertCodecPreset(); - } -} \ No newline at end of file + /// + public abstract PresetBase ConvertCodecPreset(); +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs index 61a40048..bc4e5a80 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs @@ -1,30 +1,29 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + +/// +/// Defines the required elements for layout control +/// +public interface IHasCodecLayouts { /// - /// Defines the required elements for layout control + /// Feedback that indicates the current layout on the local display /// - public interface IHasCodecLayouts - { - /// - /// Feedback that indicates the current layout on the local display - /// - StringFeedback LocalLayoutFeedback { get; } + StringFeedback LocalLayoutFeedback { get; } - /// - /// Toggles the local layout - /// - void LocalLayoutToggle(); + /// + /// Toggles the local layout + /// + void LocalLayoutToggle(); - /// - /// Toggles the local layout to single prominent - /// - void LocalLayoutToggleSingleProminent(); + /// + /// Toggles the local layout to single prominent + /// + void LocalLayoutToggleSingleProminent(); - /// - /// Toggle the MinMax layout - /// - void MinMaxLayoutToggle(); - } -} \ No newline at end of file + /// + /// Toggle the MinMax layout + /// + void MinMaxLayoutToggle(); +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs index a52670bc..80617044 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs @@ -1,35 +1,35 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + + +/// +/// Defines the requred elements for selfview control +/// +public interface IHasCodecSelfView { /// - /// Defines the requred elements for selfview control + /// Feedback that indicates whether Selfview is on /// - public interface IHasCodecSelfView - { - /// - /// Feedback that indicates whether Selfview is on - /// - BoolFeedback SelfviewIsOnFeedback { get; } + BoolFeedback SelfviewIsOnFeedback { get; } - /// - /// Setting that indicates whether the device shows selfview by default - /// - bool ShowSelfViewByDefault { get; } + /// + /// Setting that indicates whether the device shows selfview by default + /// + bool ShowSelfViewByDefault { get; } - /// - /// Turns selfview on - /// - void SelfViewModeOn(); + /// + /// Turns selfview on + /// + void SelfViewModeOn(); - /// - /// Turns selfview off - /// - void SelfViewModeOff(); + /// + /// Turns selfview off + /// + void SelfViewModeOff(); - /// - /// Toggles selfview mode - /// - void SelfViewModeToggle(); - } -} \ No newline at end of file + /// + /// Toggles selfview mode + /// + void SelfViewModeToggle(); +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs index 6ec1f8da..ef0c72ed 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs @@ -2,21 +2,21 @@ using System; -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; + + +/// +/// Describes a device that provides meeting information (like a ZoomRoom) +/// +public interface IHasMeetingInfo { /// - /// Describes a device that provides meeting information (like a ZoomRoom) + /// Raised when meeting info changes /// - public interface IHasMeetingInfo - { - /// - /// Raised when meeting info changes - /// - event EventHandler MeetingInfoChanged; + event EventHandler MeetingInfoChanged; - /// - /// Gets the current meeting information - /// - MeetingInfo MeetingInfo { get; } - } -} \ No newline at end of file + /// + /// Gets the current meeting information + /// + MeetingInfo MeetingInfo { get; } +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs index b133eebd..de4dbdd5 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs @@ -1,30 +1,29 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; + +/// +/// Defines the contract for IHasMeetingLock +/// +public interface IHasMeetingLock { /// - /// Defines the contract for IHasMeetingLock + /// Feedback that indicates whether the meeting is locked /// - public interface IHasMeetingLock - { - /// - /// Feedback that indicates whether the meeting is locked - /// - BoolFeedback MeetingIsLockedFeedback { get; } + BoolFeedback MeetingIsLockedFeedback { get; } - /// - /// Locks the meeting - /// - void LockMeeting(); + /// + /// Locks the meeting + /// + void LockMeeting(); - /// - /// Unlocks the meeting - /// - void UnLockMeeting(); + /// + /// Unlocks the meeting + /// + void UnLockMeeting(); - /// - /// Toggles the meeting lock state - /// - void ToggleMeetingLock(); - } -} \ No newline at end of file + /// + /// Toggles the meeting lock state + /// + void ToggleMeetingLock(); +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs index 96e23daa..6ec4c436 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs @@ -1,30 +1,30 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; + + +/// +/// Defines the contract for IHasMeetingRecording +/// +public interface IHasMeetingRecording { /// - /// Defines the contract for IHasMeetingRecording + /// Feedback that indicates whether the meeting is being recorded /// - public interface IHasMeetingRecording - { - /// - /// Feedback that indicates whether the meeting is being recorded - /// - BoolFeedback MeetingIsRecordingFeedback { get; } + BoolFeedback MeetingIsRecordingFeedback { get; } - /// - /// Starts recording the meeting - /// - void StartRecording(); + /// + /// Starts recording the meeting + /// + void StartRecording(); - /// - /// Stops recording the meeting - /// - void StopRecording(); + /// + /// Stops recording the meeting + /// + void StopRecording(); - /// - /// Toggles recording the meeting - /// - void ToggleRecording(); - } -} \ No newline at end of file + /// + /// Toggles recording the meeting + /// + void ToggleRecording(); +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs index 6ff549af..42869ee9 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs @@ -28,4 +28,4 @@ /// void AdmitParticipantFromWaitingRoom(int userId); } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs index b2180c39..c81152be 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs @@ -1,58 +1,57 @@ -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; + +/// +/// Defines the contract for IHasPresentationOnlyMeeting +/// +public interface IHasPresentationOnlyMeeting { /// - /// Defines the contract for IHasPresentationOnlyMeeting + /// Starts a presentation only meeting /// - 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(); - } + void StartSharingOnlyMeeting(); /// - /// Enumeration of eSharingMeetingMode values + /// Starts a presentation only meeting with specified display mode /// - public enum eSharingMeetingMode - { - /// - /// No specific sharing mode - /// - None, - /// - /// Laptop sharing mode - /// - Laptop, - /// - /// iOS sharing mode - /// - Ios, - } -} \ No newline at end of file + /// 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, +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs index 46c3d8f7..3e9b861c 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs @@ -1,25 +1,25 @@ using PepperDash.Essentials.Devices.Common.VideoCodec; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + + +/// +/// Defines the contract for IHasSelfviewPosition +/// +public interface IHasSelfviewPosition { /// - /// Defines the contract for IHasSelfviewPosition + /// Gets the SelfviewPipPositionFeedback /// - public interface IHasSelfviewPosition - { - /// - /// Gets the SelfviewPipPositionFeedback - /// - StringFeedback SelfviewPipPositionFeedback { get; } + StringFeedback SelfviewPipPositionFeedback { get; } - /// - /// Sets the selfview position - /// - void SelfviewPipPositionSet(CodecCommandWithLabel position); + /// + /// Sets the selfview position + /// + void SelfviewPipPositionSet(CodecCommandWithLabel position); - /// - /// Toggles the selfview position - /// - void SelfviewPipPositionToggle(); - } -} \ No newline at end of file + /// + /// Toggles the selfview position + /// + void SelfviewPipPositionToggle(); +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs index ab08a414..505dca64 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs @@ -1,26 +1,25 @@ using PepperDash.Essentials.Devices.Common.VideoCodec; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +/// +/// Defines the contract for IHasSelfviewSize +/// +public interface IHasSelfviewSize { /// - /// Defines the contract for IHasSelfviewSize + /// Gets the SelfviewPipSizeFeedback /// - public interface IHasSelfviewSize - { - /// - /// Gets the SelfviewPipSizeFeedback - /// - StringFeedback SelfviewPipSizeFeedback { get; } + StringFeedback SelfviewPipSizeFeedback { get; } - /// - /// Sets the selfview size - /// - /// The new selfview size - void SelfviewPipSizeSet(CodecCommandWithLabel size); + /// + /// Sets the selfview size + /// + /// The new selfview size + void SelfviewPipSizeSet(CodecCommandWithLabel size); - /// - /// Toggles the selfview size - /// - void SelfviewPipSizeToggle(); - } + /// + /// Toggles the selfview size + /// + void SelfviewPipSizeToggle(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs index d0f1333b..58247ae7 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs @@ -1,46 +1,46 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + + +/// +/// Describes a device that has Standby Mode capability +/// +public interface IHasStandbyMode { /// - /// Describes a device that has Standby Mode capability + /// Feedback that indicates whether Standby Mode is on /// - public interface IHasStandbyMode - { - /// - /// Feedback that indicates whether Standby Mode is on - /// - BoolFeedback StandbyIsOnFeedback { get; } - - /// - /// Activates Standby Mode - /// - void StandbyActivate(); - - /// - /// Deactivates Standby Mode - /// - void StandbyDeactivate(); - } + BoolFeedback StandbyIsOnFeedback { get; } /// - /// Defines the contract for IHasHalfWakeMode + /// Activates Standby Mode /// - public interface IHasHalfWakeMode : IHasStandbyMode - { - /// - /// Feedback that indicates whether Half Wake Mode is on - /// - BoolFeedback HalfWakeModeIsOnFeedback { get; } + void StandbyActivate(); - /// - /// Feedback that indicates whether the device is entering Standby Mode - /// - BoolFeedback EnteringStandbyModeFeedback { get; } + /// + /// Deactivates Standby Mode + /// + void StandbyDeactivate(); +} - /// - /// Activates Half Wake Mode - /// - void HalfwakeActivate(); - } -} \ No newline at end of file +/// +/// 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(); +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs index 357416e2..2e2f0266 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs @@ -1,24 +1,23 @@ -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; + +/// +/// Describes the ability to start an ad-hoc meeting +/// +public interface IHasStartMeeting { /// - /// Describes the ability to start an ad-hoc meeting + /// The default meeting duration in minutes /// - public interface IHasStartMeeting - { - /// - /// The default meeting duration in minutes - /// - uint DefaultMeetingDurationMin { get; } + uint DefaultMeetingDurationMin { get; } - /// - /// Start an ad-hoc meeting for the specified duration - /// - /// - void StartMeeting(uint duration); + /// + /// Start an ad-hoc meeting for the specified duration + /// + /// + void StartMeeting(uint duration); - /// - /// Leaves a meeting without ending it - /// - void LeaveMeeting(); - } + /// + /// Leaves a meeting without ending it + /// + void LeaveMeeting(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs index cdeb9190..91d2fba9 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs @@ -1,26 +1,25 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + +/// +/// For rooms that have video codec +/// +public interface IHasVideoCodec : IHasInCallFeedback, IPrivacy { /// - /// For rooms that have video codec + /// Gets the VideoCodecBase instance /// - public interface IHasVideoCodec : IHasInCallFeedback, IPrivacy - { - /// - /// Gets the VideoCodecBase instance - /// - VideoCodecBase VideoCodec { get; } + VideoCodecBase VideoCodec { get; } - /// - /// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis - /// - IntFeedback CallTypeFeedback { 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; } + /// + /// When something in the room is sharing with the far end or through other means + /// + BoolFeedback IsSharingFeedback { get; } - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs index b2583a5d..bf0fe51c 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs @@ -1,21 +1,21 @@ using PepperDash.Essentials.Devices.Common.Codec; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + + +/// +/// Defines the contract for IJoinCalls +/// +public interface IJoinCalls { /// - /// Defines the contract for IJoinCalls + /// Joins a call /// - public interface IJoinCalls - { - /// - /// Joins a call - /// - /// The active call to join - void JoinCall(CodecActiveCallItem activeCall); + /// The active call to join + void JoinCall(CodecActiveCallItem activeCall); - /// - /// Joins all calls - /// - void JoinAllCalls(); - } -} \ No newline at end of file + /// + /// Joins all calls + /// + void JoinAllCalls(); +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs index 5c7e89d8..d2fba918 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs @@ -4,299 +4,198 @@ using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Devices.Common.VideoCodec; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Cameras +namespace PepperDash.Essentials.Devices.Common.Cameras; + +public class MockVCCamera : CameraBase, IHasCameraPtzControl, IHasCameraFocusControl, IBridgeAdvanced { - /// - /// Represents a MockVCCamera - /// - public class MockVCCamera : CameraBase, IHasCameraPtzControl, IHasCameraFocusControl, IBridgeAdvanced + protected VideoCodecBase ParentCodec { get; private set; } + + + public MockVCCamera(string key, string name, VideoCodecBase codec) + : base(key, name) { - /// - /// Gets the parent video codec - /// - protected VideoCodecBase ParentCodec { get; private set; } + Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom | eCameraCapabilities.Focus; - /// - /// 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); - } + ParentCodec = codec; } - /// - /// Represents a MockFarEndVCCamera - /// - public class MockFarEndVCCamera : CameraBase, IHasCameraPtzControl, IAmFarEndCamera, IBridgeAdvanced + #region IHasCameraPtzControl Members + + public void PositionHome() { - /// - /// Gets the parent video codec - /// - protected VideoCodecBase ParentCodec { get; private set; } + Debug.LogMessage(LogEventLevel.Debug, this, "Resetting to home position"); + } - /// - /// 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; + #endregion - ParentCodec = codec; - } + #region IHasCameraPanControl Members - #region IHasCameraPtzControl Members + public void PanLeft() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Panning Left"); + } - /// - /// PositionHome method - /// - public void PositionHome() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Resetting to home position"); - } + public void PanRight() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Panning Right"); + } - #endregion + public void PanStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Pan"); + } - #region IHasCameraPanControl Members + #endregion - /// - /// PanLeft method - /// - public void PanLeft() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Panning Left"); - } + #region IHasCameraTiltControl Members - /// - /// PanRight method - /// - public void PanRight() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Panning Right"); - } + public void TiltDown() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Down"); + } - /// - /// PanStop method - /// - public void PanStop() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Pan"); - } + public void TiltUp() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Up"); + } - #endregion + public void TiltStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Tilt"); + } - #region IHasCameraTiltControl Members + #endregion - /// - /// TiltDown method - /// - public void TiltDown() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Down"); - } + #region IHasCameraZoomControl Members - /// - /// TiltUp method - /// - public void TiltUp() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Up"); - } + public void ZoomIn() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Zooming In"); + } - /// - /// TiltStop method - /// - public void TiltStop() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Tilt"); - } + public void ZoomOut() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Zooming Out"); + } - #endregion + public void ZoomStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Zoom"); + } - #region IHasCameraZoomControl Members + #endregion - /// - /// ZoomIn method - /// - public void ZoomIn() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Zooming In"); - } + #region IHasCameraFocusControl Members - /// - /// ZoomOut method - /// - public void ZoomOut() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Zooming Out"); - } + public void FocusNear() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Focusing Near"); + } - /// - /// ZoomStop method - /// - public void ZoomStop() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Zoom"); - } + public void FocusFar() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Focusing Far"); + } - #endregion + public void FocusStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Focus"); + } - /// - /// LinkToApi method - /// - public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); - } + public void TriggerAutoFocus() + { + Debug.LogMessage(LogEventLevel.Debug, this, "AutoFocus Triggered"); + } + + #endregion + + public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); + } +} + +public class MockFarEndVCCamera : CameraBase, IHasCameraPtzControl, IAmFarEndCamera, IBridgeAdvanced +{ + protected VideoCodecBase ParentCodec { get; private set; } + + + public MockFarEndVCCamera(string key, string name, VideoCodecBase codec) + : base(key, name) + { + Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom; + + ParentCodec = codec; + } + + #region IHasCameraPtzControl Members + + public void PositionHome() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Resetting to home position"); + } + + #endregion + + #region IHasCameraPanControl Members + + public void PanLeft() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Panning Left"); + } + + public void PanRight() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Panning Right"); + } + + public void PanStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Pan"); + } + + #endregion + + #region IHasCameraTiltControl Members + + public void TiltDown() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Down"); + } + + public void TiltUp() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Up"); + } + + public void TiltStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Tilt"); + } + + #endregion + + #region IHasCameraZoomControl Members + + public void ZoomIn() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Zooming In"); + } + + public void ZoomOut() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Zooming Out"); + } + + public void ZoomStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Zoom"); + } + + #endregion + + public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs index 0c5654d6..aa0bcadd 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs @@ -2,32 +2,32 @@ using Newtonsoft.Json; using PepperDash.Essentials.Devices.Common.Codec; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + + +/// +/// Represents a MockVcPropertiesConfig +/// +public class MockVcPropertiesConfig { /// - /// Represents a MockVcPropertiesConfig + /// Gets or sets the Favorites /// - public class MockVcPropertiesConfig + [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() { - /// - /// 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(); - } + Favorites = new List(); + Presets = new List(); } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs index fbc73852..65d89d85 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs @@ -21,674 +21,641 @@ using Serilog.Events; using Feedback = PepperDash.Essentials.Core.Feedback; using System.Text; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + +public abstract class VideoCodecBase : ReconfigurableDevice, IRoutingInputsOutputs, + IUsageTracking, IHasDialer, IHasContentSharing, ICodecAudio, iVideoCodecInfo, IBridgeAdvanced, IHasStandbyMode { + private const int XSigEncoding = 28591; + protected const int MaxParticipants = 50; + private readonly byte[] _clearBytes = XSigHelpers.ClearOutputs(); + + private readonly IHasDirectory _directoryCodec; + private readonly BasicTriList _directoryTrilist; + private readonly VideoCodecControllerJoinMap _directoryJoinmap; + + protected string _timeFormatSpecifier; + /// - /// Base class for video codec devices + /// Date format specifier /// - public abstract class VideoCodecBase : ReconfigurableDevice, IRoutingInputsOutputs, - IUsageTracking, IHasDialer, IHasContentSharing, ICodecAudio, iVideoCodecInfo, IBridgeAdvanced, IHasStandbyMode + protected string _dateFormatSpecifier; + + /// + /// Initializes a new instance of the class. + /// + protected VideoCodecBase(DeviceConfig config) + : base(config) { - private const int XSigEncoding = 28591; - /// - /// Maximum number of participants - /// - protected const int MaxParticipants = 50; - private readonly byte[] _clearBytes = XSigHelpers.ClearOutputs(); + 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); - /// - /// Time format specifier - /// - protected string _timeFormatSpecifier; + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + MeetingsToDisplayFeedback = new IntFeedback(() => MeetingsToDisplay); - /// - /// Date format specifier - /// - protected string _dateFormatSpecifier; + InputPorts = new RoutingPortCollection(); + OutputPorts = new RoutingPortCollection(); - /// - /// Initializes a new instance of the class. - /// - protected VideoCodecBase(DeviceConfig config) - : base(config) + 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; } + + public bool SupportsCameraOff { get; protected set; } + public bool SupportsCameraAutoMode { get; protected set; } + + /// + /// Gets or sets the IsReady + /// + public bool IsReady { get; protected set; } + + /// + public virtual List Feedbacks + { + get { - - 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 { - 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; + PrivacyModeIsOnFeedback, + SharingSourceFeedback }; } + } - /// - /// 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) + /// + /// 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 { - Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist {0}", trilist.ID.ToString("X")); + var value = ActiveCalls != null && ActiveCalls.Any(c => c.IsActiveCall); + return value; + } + } - LinkVideoCodecDtmfToApi(trilist, joinMap); + /// + /// Dials the specified number + /// + public abstract void Dial(string number); - LinkVideoCodecCallControlsToApi(trilist, joinMap); + /// + /// Ends the specified call + /// + public abstract void EndCall(CodecActiveCallItem call); - LinkVideoCodecContentSharingToApi(trilist, joinMap); + /// + /// Ends all active calls + /// + public abstract void EndAllCalls(); - LinkVideoCodecPrivacyToApi(trilist, joinMap); + /// + /// Accepts the specified call + /// + public abstract void AcceptCall(CodecActiveCallItem call); - LinkVideoCodecVolumeToApi(trilist, joinMap); + /// + /// Rejects the specified call + /// + public abstract void RejectCall(CodecActiveCallItem call); - LinkVideoCodecInfoToApi(trilist, joinMap); + /// + /// Sends DTMF tones + /// + public abstract void SendDtmf(string s); + public virtual void SendDtmf(string s, CodecActiveCallItem call) { } - // 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); - } - }; + #endregion - if (codec is ICommunicationMonitor) + #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) { - LinkVideoCodecCommMonitorToApi(codec as ICommunicationMonitor, trilist, joinMap); + 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 IHasCodecSelfView) + if (codec is IHasScheduleAwareness) { - LinkVideoCodecSelfviewToApi(codec as IHasCodecSelfView, trilist, joinMap); + (codec as IHasScheduleAwareness).GetSchedule(); + } + + if (codec is IHasParticipants) + { + UpdateParticipantsXSig((codec as IHasParticipants).Participants.CurrentParticipants); } if (codec is IHasCameraAutoMode) { trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, SupportsCameraAutoMode); - LinkVideoCodecCameraModeToApi(codec as IHasCameraAutoMode, trilist, joinMap); + + (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) { - 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]); + (codec as IHasCameraOff).CameraIsOffFeedback.FireUpdate(); } if (codec is IHasPhoneDialing) { - LinkVideoCodecPhoneToApi(codec as IHasPhoneDialing, trilist, joinMap); + (codec as IHasPhoneDialing).PhoneOffHookFeedback.FireUpdate(); } if (codec is IHasCallHistory) { - LinkVideoCodecCallHistoryToApi(codec as IHasCallHistory, trilist, joinMap); + UpdateCallHistory((codec as IHasCallHistory), trilist, joinMap); } - trilist.OnlineStatusChange += (device, args) => + 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) { - if (!args.DeviceOnLine) return; + 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); + } + }; + } - if (codec is IHasDirectory) - { - (codec as IHasDirectory).SetCurrentDirectoryToRoot(); - } + private void LinkVideoCodecPhoneToApi(IHasPhoneDialing codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + codec.PhoneOffHookFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PhoneHookState.JoinNumber]); - if (codec is IHasScheduleAwareness) - { - (codec as IHasScheduleAwareness).GetSchedule(); - } + trilist.SetSigFalseAction(joinMap.DialPhone.JoinNumber, + () => codec.DialPhoneCall(trilist.StringOutput[joinMap.PhoneDialString.JoinNumber].StringValue)); - if (codec is IHasParticipants) - { - UpdateParticipantsXSig((codec as IHasParticipants).Participants.CurrentParticipants); - } + trilist.SetSigFalseAction(joinMap.HangUpPhone.JoinNumber, codec.EndPhoneCall); + } - if (codec is IHasCameraAutoMode) - { - trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, SupportsCameraAutoMode); + private void LinkVideoCodecSelfviewPositionToApi(IHasSelfviewPosition codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetSigFalseAction(joinMap.SelfviewPosition.JoinNumber, codec.SelfviewPipPositionToggle); - (codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate(); - } + codec.SelfviewPipPositionFeedback.LinkInputSig(trilist.StringInput[joinMap.SelfviewPositionFb.JoinNumber]); + } - if (codec is IHasCodecSelfView) - { - (codec as IHasCodecSelfView).SelfviewIsOnFeedback.FireUpdate(); - } + private void LinkVideoCodecCameraOffToApi(IHasCameraOff codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetSigFalseAction(joinMap.CameraModeOff.JoinNumber, codec.CameraOff); - 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) + codec.CameraIsOffFeedback.OutputChange += (o, a) => { - 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) + if (a.BoolValue) { trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); @@ -699,822 +666,834 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - if (!(codec is IHasCameraAutoMode autoModeCodec)) return; + if (!(codec is IHasCameraAutoMode autoCodec)) return; - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); + 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; } - private void LinkVideoCodecVolumeToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMuteOn.JoinNumber]); - MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - 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]); + if (!(codec is IHasCameraAutoMode autoModeCodec)) return; - trilist.SetBoolSigAction(joinMap.VolumeUp.JoinNumber, VolumeUp); - trilist.SetBoolSigAction(joinMap.VolumeDown.JoinNumber, VolumeDown); + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); + } - trilist.SetUShortSigAction(joinMap.VolumeLevel.JoinNumber, SetVolume); + 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); - private void LinkVideoCodecPrivacyToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - PrivacyModeIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.MicMuteOn.JoinNumber]); - PrivacyModeIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.MicMuteOff.JoinNumber]); + VolumeLevelFeedback.LinkInputSig(trilist.UShortInput[joinMap.VolumeLevel.JoinNumber]); - trilist.SetSigFalseAction(joinMap.MicMuteOn.JoinNumber, PrivacyModeOn); - trilist.SetSigFalseAction(joinMap.MicMuteOff.JoinNumber, PrivacyModeOff); - trilist.SetSigFalseAction(joinMap.MicMuteToggle.JoinNumber, PrivacyModeToggle); - } + trilist.SetBoolSigAction(joinMap.VolumeUp.JoinNumber, VolumeUp); + trilist.SetBoolSigAction(joinMap.VolumeDown.JoinNumber, VolumeDown); - private void LinkVideoCodecCommMonitorToApi(ICommunicationMonitor codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - codec.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); - } + trilist.SetUShortSigAction(joinMap.VolumeLevel.JoinNumber, SetVolume); - 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) => + 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) => { - SetParticipantActions(trilist, joinMap, codec.Participants.CurrentParticipants); - - UpdateParticipantsXSig(codec, trilist, joinMap); + if (sender.IsOnline) + { + 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) + // set actions and update the values when the list changes + codec.Participants.ParticipantsListHasChanged += (sender, args) => { - string participantsXSig; + SetParticipantActions(trilist, joinMap, codec.Participants.CurrentParticipants); - if (codec.Participants.CurrentParticipants.Count == 0) - { - participantsXSig = Encoding.GetEncoding(XSigEncoding).GetString(_clearBytes, 0, _clearBytes.Length); - trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig); - trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count); - return; - } + UpdateParticipantsXSig(codec, trilist, joinMap); + }; - participantsXSig = UpdateParticipantsXSig(codec.Participants.CurrentParticipants); + 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; } - /// - /// Sets the actions for each participant in the list - /// - private void SetParticipantActions(BasicTriList trilist, VideoCodecControllerJoinMap joinMap, List currentParticipants) + 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) { - uint index = 0; // track the index of the participant in the + var p = participant; + if (index > MaxParticipants) break; - foreach (var participant in currentParticipants) + if (this is IHasParticipantAudioMute audioMuteCodec) { - var p = participant; - if (index > MaxParticipants) break; + trilist.SetSigFalseAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index, + () => audioMuteCodec.ToggleAudioForParticipant(p.UserId)); - 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++; + trilist.SetSigFalseAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index, + () => audioMuteCodec.ToggleVideoForParticipant(p.UserId)); } - // Clear out any previously set actions - while (index < MaxParticipants) + if (this is IHasParticipantPinUnpin pinCodec) { - trilist.ClearBoolSigAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index); - trilist.ClearBoolSigAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index); - trilist.ClearBoolSigAction(joinMap.ParticipantPinToggleStart.JoinNumber + index); - - index++; + trilist.SetSigFalseAction(joinMap.ParticipantPinToggleStart.JoinNumber + index, + () => pinCodec.ToggleParticipantPinState(p.UserId, pinCodec.ScreenIndexToPinUserTo)); } + + index++; } - private string UpdateParticipantsXSig(List currentParticipants) + // Clear out any previously set actions + while (index < MaxParticipants) { - 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; + trilist.ClearBoolSigAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index); + trilist.ClearBoolSigAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index); + trilist.ClearBoolSigAction(joinMap.ParticipantPinToggleStart.JoinNumber + index); - var tokenArray = new XSigToken[maxParticipants * offset]; + index++; + } + } - foreach (var participant in currentParticipants) - { - if (meetingIndex >= maxParticipants * offset) break; + 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; - // 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 - // ); + 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); + //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())); + 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); + //serials + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, participant.Name); - //analogs - tokenArray[analogIndex] = new XSigAnalogToken(analogIndex + 1, (ushort)participant.ScreenIndexIsPinnedToFb); + //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; + digitalIndex += maxDigitals; + meetingIndex += offset; + stringIndex += maxStrings; + analogIndex += maxAnalogs; } - private void LinkVideoCodecContentSharingToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + while (meetingIndex < maxParticipants * offset) { - SharingContentIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.SourceShareStart.JoinNumber]); - SharingContentIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.SourceShareEnd.JoinNumber]); + //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); - SharingSourceFeedback.LinkInputSig(trilist.StringInput[joinMap.CurrentSource.JoinNumber]); + //serials + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); - trilist.SetSigFalseAction(joinMap.SourceShareStart.JoinNumber, StartSharing); - trilist.SetSigFalseAction(joinMap.SourceShareEnd.JoinNumber, StopSharing); + //analogs + tokenArray[analogIndex] = new XSigAnalogToken(analogIndex + 1, 0); - trilist.SetBoolSigAction(joinMap.SourceShareAutoStart.JoinNumber, b => AutoShareContentWhileInCall = b); + digitalIndex += maxDigitals; + meetingIndex += offset; + stringIndex += maxStrings; + analogIndex += maxAnalogs; } - private List _currentMeetings = new List(); + var returnString = GetXSigString(tokenArray); - private void LinkVideoCodecScheduleToApi(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + //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) => { - trilist.SetSigFalseAction(joinMap.UpdateMeetings.JoinNumber, codec.GetSchedule); + codec.CodecSchedule.MeetingWarningMinutes = i; + }); - trilist.SetUShortSigAction(joinMap.MinutesBeforeMeetingStart.JoinNumber, (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, () => { - codec.CodecSchedule.MeetingWarningMinutes = i; + 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]); }); - - - 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) + 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); + }; + } + + + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + private int _meetingsToDisplay = 3; + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + protected int MeetingsToDisplay + { + get { return _meetingsToDisplay; } + set + { + _meetingsToDisplay = (ushort)(value == 0 ? 3 : value); + MeetingsToDisplayFeedback.FireUpdate(); + } + } + + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + 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; - _currentMeetings = codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList(); + if (meeting.StartTime < currentTime && meeting.EndTime < currentTime) continue; - if (_currentMeetings.Count == 0) + if (meetingIndex >= _meetingsToDisplay * offset) { - var emptyXSigByteArray = XSigHelpers.ClearOutputs(); - var emptyXSigString = Encoding.GetEncoding(XSigEncoding) - .GetString(emptyXSigByteArray, 0, emptyXSigByteArray.Length); + Debug.LogMessage(LogEventLevel.Verbose, this, "Max Meetings reached"); + break; + } - trilist.SetString(joinMap.Schedule.JoinNumber, emptyXSigString); + //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(string.IsNullOrEmpty(_dateFormatSpecifier) ? "d" : _dateFormatSpecifier, Global.Culture)); + tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, meeting.StartTime.ToString(string.IsNullOrEmpty(_timeFormatSpecifier) ? "t" : _timeFormatSpecifier, Global.Culture)); + tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, meeting.EndTime.ToString(string.IsNullOrEmpty(_dateFormatSpecifier) ? "d" : _dateFormatSpecifier, Global.Culture)); + tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, meeting.EndTime.ToString(string.IsNullOrEmpty(_timeFormatSpecifier) ? "t" : _timeFormatSpecifier, 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(_directoryCodec, 0, _directoryTrilist, _directoryJoinmap)); + + // 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; } - 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; + trilist.SetString(joinMap.DirectoryEntrySelectedNumber.JoinNumber, + selectedContact != null ? selectedContact.ContactMethods[0].Number : string.Empty); - // TODO [ ] Issue #868 - trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC"); - UpdateMeetingsListXSig(_currentMeetings); - }; + if (!(_selectedDirectoryItem is DirectoryContact entryToDial)) return; + + Dial(entryToDial.ContactMethods[0].Number); } - - - - private int _meetingsToDisplay = 3; - - /// - /// Gets or sets the number of meetings to display on the XSIG - /// - protected int MeetingsToDisplay + else { - get { return _meetingsToDisplay; } - set + // If auto dial is disabled... + + if (!(_selectedDirectoryItem is DirectoryContact entryToDial)) { - _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); + // Clear out values and actions from last selected item 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); + trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, (ushort)entryToDial.ContactMethods.Count); - var selectedContact = _selectedDirectoryItem as DirectoryContact; - - if (selectedContact != null && selectedContact.ContactMethods.Count >= 1) + // Update the action to dial the selected contact method + trilist.SetUShortSigAction(joinMap.SelectContactMethod.JoinNumber, (u) => { - trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, true); + 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; } - trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, - selectedContact != null ? selectedContact.Name : string.Empty); + tokenArray[arrayIndex] = new XSigSerialToken(entryIndex, entry.Name); - // Allow auto dial of selected line. Always dials first contact method - if (!trilist.GetBool(joinMap.DirectoryDisableAutoDialSelectedLine.JoinNumber)) + 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) { - 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); + 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 { - // If auto dial is disabled... + trilist.SetString(joinMap.IncomingCallName.JoinNumber, string.Empty); + trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, string.Empty); + } - 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); + trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); - // Update the action to dial the selected contact method - trilist.SetUShortSigAction(joinMap.SelectContactMethod.JoinNumber, (u) => - { - if (u < 1 || u > entryToDial.ContactMethods.Count) return; + trilist.SetUshort(joinMap.ConnectedCallCount.JoinNumber, (ushort)ActiveCalls.Count); + }; - trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber, () => Dial(entryToDial.ContactMethods[u - 1].Number)); - }); + if (this is IJoinCalls joinCodec) + { + trilist.SetSigFalseAction(joinMap.JoinAllCalls.JoinNumber, () => joinCodec.JoinAllCalls()); - // 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); + 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); + } + }); } } - /// - /// Generates the XSig data representing the available contact methods for the selected DirectoryContact - /// - /// - /// - private string UpdateContactMethodsXSig(DirectoryContact contact) + if (this is IHasCallHold holdCodec) { - 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) + trilist.SetSigFalseAction(joinMap.HoldAllCalls.JoinNumber, () => { - if (arrayIndex >= maxMethods * offset) - break; + foreach (var call in ActiveCalls) + { + holdCodec.HoldCall(call); + } + }); - //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) + for (int i = 0; i < joinMap.HoldCallsStart.JoinSpan; i++) { - 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); + var index = i; - arrayIndex += offset; - stringIndex += maxStrings; + 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); + } + }); } - - 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) => + trilist.OnlineStatusChange += (device, args) => { if (!args.DeviceOnLine) return; @@ -1524,159 +1503,136 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec 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; } - private string UpdateCallStatusXSig() + 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)) { - 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) + SendDtmf(s); + } + else + { + var callIndex = trilist.GetUshort(joinMap.SelectCall.JoinNumber); + if (callIndex > 0 && callIndex <= 8) { - 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) + var call = ActiveCalls[callIndex - 1]; + if (call != null && call.IsActiveCall) { - // 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); - } + SendDtmf(s, call); } else { - Debug.LogMessage(LogEventLevel.Information, this, "Warning: Invalid call index specified. Please use a value of 1-8."); + Debug.LogMessage(LogEventLevel.Information, this, "Warning: No call found at index {0} or call is not active.", callIndex); } } - } - - 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) => + else { - 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; - } + Debug.LogMessage(LogEventLevel.Information, this, "Warning: Invalid call index specified. Please use a value of 1-8."); + } + } + } - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - return; - } + private void LinkVideoCodecCameraLayoutsToApi(IHasCodecLayouts codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetSigFalseAction(joinMap.CameraLayout.JoinNumber, codec.LocalLayoutToggle); - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - }; + 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); - if (codec is IHasCameraOff offModeCodec) + codec.CameraAutoModeIsOnFeedback.OutputChange += (o, a) => + { + if (codec is IHasCameraOff offCodec) { - if (offModeCodec.CameraIsOffFeedback.BoolValue) + if (offCodec.CameraIsOffFeedback.BoolValue) { trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); @@ -1684,360 +1640,383 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec return; } - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); + 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; } - private void LinkVideoCodecSelfviewToApi(IHasCodecSelfView codec, BasicTriList trilist, - VideoCodecControllerJoinMap joinMap) - { - trilist.SetSigFalseAction(joinMap.CameraSelfView.JoinNumber, codec.SelfViewModeToggle); + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); + } - codec.SelfviewIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.CameraSelfView.JoinNumber]); + 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, ""); + } } - private void LinkVideoCodecCameraToApi(IHasCodecCameras codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + //Camera Select + trilist.SetUShortSigAction(joinMap.CameraNumberSelect.JoinNumber, (i) => { - //Camera PTZ - trilist.SetBoolSigAction(joinMap.CameraTiltUp.JoinNumber, (b) => + if (i > 0 && i <= codec.Cameras.Count) { - 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) => + codec.SelectCamera(codec.Cameras[i - 1].Key); + } + else { - if (codec.SelectedCamera == null) return; + Debug.LogMessage(LogEventLevel.Information, this, "Unable to select. No camera found at index {0}", i); + } + }); - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + // Set initial selected camera feedback + if (codec.SelectedCamera != null) + { + trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)codec.Cameras.FindIndex((c) => c.Key == codec.SelectedCamera.Key)); + } - if (b) camera.TiltDown(); - else camera.TiltStop(); - }); - trilist.SetBoolSigAction(joinMap.CameraPanLeft.JoinNumber, (b) => + 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) { - 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, ""); - } + return; } - //Camera Select - trilist.SetUShortSigAction(joinMap.CameraNumberSelect.JoinNumber, (i) => + if (!(args.SelectedCamera is IHasCameraPresets)) { - 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)); + return; } - codec.CameraSelected += (sender, args) => - { - var i = (ushort)codec.Cameras.FindIndex((c) => c.Key == args.SelectedCamera.Key); + var cam = args.SelectedCamera as IHasCameraPresets; + SetCameraPresetNames(cam.Presets); - trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)(i + 1)); + (args.SelectedCamera as IHasCameraPresets).PresetsListHasChanged += (o, eventArgs) => SetCameraPresetNames(cam.Presets); - 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, - () => + trilist.SetUShortSigAction(joinMap.CameraPresetSelect.JoinNumber, + (a) => { - cam.PresetStore(trilist.UShortOutput[joinMap.CameraPresetSelect.JoinNumber].UShortValue, - String.Empty); - trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000); + cam.PresetSelect(a); + trilist.SetUshort(joinMap.CameraPresetSelect.JoinNumber, a); }); - }; - - 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); + 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; } - var xSig = s.ToArray(); + _selectedRecentCallItemIndex = (int)(u - 1); + trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, u); - returnString = Encoding.GetEncoding(XSigEncoding).GetString(xSig, 0, xSig.Length); - } + var _selectedRecentCallItem = codec.CallHistory.RecentCalls[_selectedRecentCallItemIndex]; - return returnString; + 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; } - #endregion + //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); + } } -} \ No newline at end of file + + 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 +} + + diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/ContentTypes.cs b/src/PepperDash.Essentials.MobileControl.Messengers/ContentTypes.cs index ab60d3f7..67aea972 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/ContentTypes.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/ContentTypes.cs @@ -8,16 +8,16 @@ namespace PepperDash.Essentials.AppServer /// public class SourceSelectMessageContent { - - [JsonProperty("sourceListItemKey")] /// /// Gets or sets the SourceListItemKey /// + [JsonProperty("sourceListItemKey")] public string SourceListItemKey { get; set; } - [JsonProperty("sourceListKey")] /// /// Gets or sets the SourceListKey /// + [JsonProperty("sourceListKey")] + public string SourceListKey { get; set; } } @@ -27,20 +27,20 @@ namespace PepperDash.Essentials.AppServer public class DirectRoute { - [JsonProperty("sourceKey")] /// /// Gets or sets the SourceKey /// + [JsonProperty("sourceKey")] public string SourceKey { get; set; } - [JsonProperty("destinationKey")] /// /// Gets or sets the DestinationKey /// + [JsonProperty("destinationKey")] public string DestinationKey { get; set; } - [JsonProperty("signalType")] /// /// Gets or sets the SignalType /// + [JsonProperty("signalType")] public eRoutingSignalType SignalType { get; set; } } @@ -52,4 +52,4 @@ namespace PepperDash.Essentials.AppServer /// Delegate for PressAndHoldAction /// public delegate void PressAndHoldAction(bool b); -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/DisplayBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/DisplayBaseMessenger.cs index 349b8d58..5ce9261e 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/DisplayBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/DisplayBaseMessenger.cs @@ -15,11 +15,18 @@ namespace PepperDash.Essentials.Room.MobileControl { private readonly DisplayBase display; + /// + /// Create an instance of the class. + /// + /// + /// + /// public DisplayBaseMessenger(string key, string messagePath, DisplayBase device) : base(key, messagePath, device) { display = device; } + /// protected override void RegisterActions() { base.RegisterActions(); @@ -60,4 +67,4 @@ namespace PepperDash.Essentials.Room.MobileControl }); } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IChannelMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IChannelMessenger.cs index 505fd214..8d185804 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IChannelMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IChannelMessenger.cs @@ -11,11 +11,18 @@ namespace PepperDash.Essentials.Room.MobileControl { private readonly IChannel channelDevice; + /// + /// Create an instance of the class. + /// + /// + /// + /// public IChannelMessenger(string key, string messagePath, IChannel device) : base(key, messagePath, device as IKeyName) { channelDevice = device; } + /// protected override void RegisterActions() { base.RegisterActions(); diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IColorMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IColorMessenger.cs index cef6111f..2a50c4a8 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IColorMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IColorMessenger.cs @@ -10,11 +10,19 @@ namespace PepperDash.Essentials.Room.MobileControl public class IColorMessenger : MessengerBase { private readonly IColor colorDevice; + + /// + /// Create an instance of the class. + /// + /// + /// + /// public IColorMessenger(string key, string messagePath, IColor device) : base(key, messagePath, device as IKeyName) { colorDevice = device as IColor; } + /// protected override void RegisterActions() { base.RegisterActions(); diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDPadMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDPadMessenger.cs index 92c21a0b..d7207e09 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDPadMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDPadMessenger.cs @@ -10,12 +10,19 @@ namespace PepperDash.Essentials.Room.MobileControl public class IDPadMessenger : MessengerBase { private readonly IDPad dpadDevice; + + /// + /// Create an instance of the class. + /// + /// + /// + /// public IDPadMessenger(string key, string messagePath, IDPad device) : base(key, messagePath, device as IKeyName) { dpadDevice = device; } - + /// protected override void RegisterActions() { base.RegisterActions(); diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDvrMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDvrMessenger.cs index f0ae426c..08b1d100 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDvrMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDvrMessenger.cs @@ -1,3 +1,4 @@ + using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; @@ -10,11 +11,20 @@ namespace PepperDash.Essentials.Room.MobileControl public class IDvrMessenger : MessengerBase { private readonly IDvr dvrDevice; + + /// + /// Create an instance of the class. + /// + /// + /// + /// public IDvrMessenger(string key, string messagePath, IDvr device) : base(key, messagePath, device as IKeyName) { dvrDevice = device; } + + /// protected override void RegisterActions() { base.RegisterActions(); @@ -24,4 +34,4 @@ namespace PepperDash.Essentials.Room.MobileControl } } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IHasPowerMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IHasPowerMessenger.cs index 864c20bf..247b533d 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IHasPowerMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IHasPowerMessenger.cs @@ -10,11 +10,20 @@ namespace PepperDash.Essentials.Room.MobileControl public class IHasPowerMessenger : MessengerBase { private readonly IHasPowerControl powerDevice; + + /// + /// Create an instance of the class. + /// + /// + /// + /// public IHasPowerMessenger(string key, string messagePath, IHasPowerControl device) : base(key, messagePath, device as IKeyName) { powerDevice = device; } + + /// protected override void RegisterActions() { base.RegisterActions(); diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/INumericMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/INumericMessenger.cs index d07331d2..746caf18 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/INumericMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/INumericMessenger.cs @@ -10,11 +10,20 @@ namespace PepperDash.Essentials.Room.MobileControl public class INumericKeypadMessenger : MessengerBase { private readonly INumericKeypad keypadDevice; + + /// + /// Create an instance of the class. + /// + /// + /// + /// public INumericKeypadMessenger(string key, string messagePath, INumericKeypad device) : base(key, messagePath, device as IKeyName) { keypadDevice = device; } + + /// protected override void RegisterActions() { base.RegisterActions(); diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ISetTopBoxControlsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ISetTopBoxControlsMessenger.cs index f87480bd..5e5a286d 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ISetTopBoxControlsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ISetTopBoxControlsMessenger.cs @@ -1,3 +1,4 @@ + using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; @@ -10,11 +11,20 @@ namespace PepperDash.Essentials.Room.MobileControl public class ISetTopBoxControlsMessenger : MessengerBase { private readonly ISetTopBoxControls stbDevice; + + /// + /// Create an instance of the class. + /// + /// + /// + /// public ISetTopBoxControlsMessenger(string key, string messagePath, ISetTopBoxControls device) : base(key, messagePath, device as IKeyName) { stbDevice = device; } + + /// protected override void RegisterActions() { base.RegisterActions(); @@ -35,8 +45,11 @@ namespace PepperDash.Essentials.Room.MobileControl } } + /// + /// Represents the state of a ISetTopBoxControls device to be sent to mobile clients + /// public class SetTopBoxControlsState : DeviceStateMessageBase { } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ITransportMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ITransportMessenger.cs index 0943fc0b..9eba0848 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ITransportMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ITransportMessenger.cs @@ -1,3 +1,4 @@ + using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; @@ -10,11 +11,19 @@ namespace PepperDash.Essentials.Room.MobileControl public class ITransportMessenger : MessengerBase { private readonly ITransport transportDevice; + + /// + /// Create an instance of the class. + /// + /// + /// + /// public ITransportMessenger(string key, string messagePath, ITransport device) : base(key, messagePath, device as IKeyName) { transportDevice = device; } + /// protected override void RegisterActions() { base.RegisterActions(); @@ -30,4 +39,4 @@ namespace PepperDash.Essentials.Room.MobileControl } } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs index 876bcafe..15e645a6 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs @@ -94,7 +94,10 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class DeviceInfoStateMessage : DeviceStateMessageBase { + /// + /// Gets or sets the device information associated with this message. This property contains detailed information + /// [JsonProperty("deviceInfo")] public DeviceInfo DeviceInfo { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs index 81df6bac..ff38a784 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs @@ -169,10 +169,10 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class VolumeStateMessage : DeviceStateMessageBase { - [JsonProperty("volume", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the Volume /// + [JsonProperty("volume", NullValueHandling = NullValueHandling.Ignore)] public Volume Volume { get; set; } } @@ -181,27 +181,42 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class Volume { + /// + /// Gets or sets the Level + /// [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] public int? Level { get; set; } + + /// + /// Gets or sets the HasMute + /// [JsonProperty("hasMute", NullValueHandling = NullValueHandling.Ignore)] public bool? HasMute { get; set; } + + /// + /// Gets or sets the Muted + /// [JsonProperty("muted", NullValueHandling = NullValueHandling.Ignore)] public bool? Muted { get; set; } - [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Label /// + [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)] public string Label { get; set; } - [JsonProperty("rawValue", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the RawValue /// + [JsonProperty("rawValue", NullValueHandling = NullValueHandling.Ignore)] public string RawValue { get; set; } + /// + /// Gets or sets the Units + /// [JsonConverter(typeof(StringEnumConverter))] [JsonProperty("units", NullValueHandling = NullValueHandling.Ignore)] public eVolumeLevelUnits? Units { get; set; } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs index 83def192..e6a334d3 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs @@ -32,4 +32,4 @@ namespace PepperDash.Essentials.AppServer.Messengers PostStatusMessage(state, id); } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs index 79622a41..e2bd1be5 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs @@ -87,4 +87,4 @@ namespace PepperDash.Essentials.AppServer.Messengers } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs index 92674574..fff90dab 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs @@ -12,12 +12,20 @@ namespace PepperDash.Essentials.AppServer.Messengers { private readonly IDspPresets device; + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// public IDspPresetsMessenger(string key, string messagePath, IDspPresets device) : base(key, messagePath, device as IKeyName) { this.device = device; } + + /// protected override void RegisterActions() { base.RegisterActions(); @@ -54,7 +62,11 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class IHasDspPresetsStateMessage : DeviceStateMessageBase { + /// + /// Gets or sets the presets. + /// The key is the preset key, and the value is the preset name + /// [JsonProperty("presets")] public Dictionary Presets { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs index 966d8d77..f705317e 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs @@ -214,4 +214,4 @@ namespace PepperDash.Essentials.AppServer.Messengers } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs index 6c0f1a0a..2a8dd5bc 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs @@ -73,4 +73,4 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("currentSource")] public SourceListItem CurrentSource { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs index 57ab2617..8d8949ed 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs @@ -26,6 +26,8 @@ namespace PepperDash.Essentials.AppServer.Messengers itemDevice = device; } + + /// protected override void RegisterActions() { base.RegisterActions(); @@ -90,10 +92,10 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class IHasInputsStateMessage : DeviceStateMessageBase { - [JsonProperty("inputs")] /// /// Gets or sets the Inputs /// + [JsonProperty("inputs")] public Inputs Inputs { get; set; } } @@ -102,14 +104,18 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class Inputs { + /// + /// Gets or sets the Items + /// The key is the input key, and the value is the input name + /// [JsonProperty("items")] public Dictionary Items { get; set; } - [JsonProperty("currentItem")] /// /// Gets or sets the CurrentItem /// + [JsonProperty("currentItem")] public TKey CurrentItem { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs index 525a6d6d..b16611cf 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs @@ -70,4 +70,4 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("powerState", NullValueHandling = NullValueHandling.Ignore)] public bool? PowerState { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs index 76598cee..affd2d95 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs @@ -5,114 +5,76 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Devices.Common.Codec; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class IHasScheduleAwarenessMessenger : MessengerBase { - /// - /// Represents a IHasScheduleAwarenessMessenger - /// - public class IHasScheduleAwarenessMessenger : MessengerBase + public IHasScheduleAwareness ScheduleSource { get; private set; } + + public IHasScheduleAwarenessMessenger(string key, IHasScheduleAwareness scheduleSource, string messagePath) + : base(key, messagePath, scheduleSource as IKeyName) { - /// - /// Gets or sets the ScheduleSource - /// - public IHasScheduleAwareness ScheduleSource { get; private set; } + ScheduleSource = scheduleSource ?? throw new ArgumentNullException("scheduleSource"); + ScheduleSource.CodecSchedule.MeetingsListHasChanged += new EventHandler(CodecSchedule_MeetingsListHasChanged); + ScheduleSource.CodecSchedule.MeetingEventChange += new EventHandler(CodecSchedule_MeetingEventChange); + } - public IHasScheduleAwarenessMessenger(string key, IHasScheduleAwareness scheduleSource, string messagePath) - : base(key, messagePath, scheduleSource as IKeyName) + protected override void RegisterActions() + { + AddAction("/schedule/fullStatus", (id, content) => SendFullScheduleObject()); + } + + private void CodecSchedule_MeetingEventChange(object sender, MeetingEventArgs e) + { + PostStatusMessage(JToken.FromObject(new MeetingChangeMessage { - 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 { - MeetingChange = new MeetingChange - { - ChangeType = e.ChangeType.ToString(), - Meeting = e.Meeting - } - }) - ); - } + ChangeType = e.ChangeType.ToString(), + Meeting = e.Meeting + } + }) + ); + } - private void CodecSchedule_MeetingsListHasChanged(object sender, EventArgs e) + private void CodecSchedule_MeetingsListHasChanged(object sender, EventArgs e) + { + SendFullScheduleObject(); + } + + /// + /// Helper method to send the full schedule data + /// + private void SendFullScheduleObject() + { + PostStatusMessage(new FullScheduleMessage { - 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); - } + Meetings = ScheduleSource.CodecSchedule.Meetings, + MeetingWarningMinutes = ScheduleSource.CodecSchedule.MeetingWarningMinutes + }); } +} - /// - /// Represents a FullScheduleMessage - /// - public class FullScheduleMessage : DeviceStateMessageBase - { +public class FullScheduleMessage : DeviceStateMessageBase +{ + [JsonProperty("meetings", NullValueHandling = NullValueHandling.Ignore)] + public List Meetings { get; set; } - /// - /// Gets or sets the Meetings - /// - [JsonProperty("meetings", NullValueHandling = NullValueHandling.Ignore)] - public List Meetings { get; set; } + [JsonProperty("meetingWarningMinutes", NullValueHandling = NullValueHandling.Ignore)] + public int MeetingWarningMinutes { get; set; } +} +public class MeetingChangeMessage +{ + [JsonProperty("meetingChange", NullValueHandling = NullValueHandling.Ignore)] + public MeetingChange MeetingChange { get; set; } +} - /// - /// Gets or sets the MeetingWarningMinutes - /// - [JsonProperty("meetingWarningMinutes", NullValueHandling = NullValueHandling.Ignore)] - public int MeetingWarningMinutes { get; set; } - } +public class MeetingChange +{ + [JsonProperty("changeType", NullValueHandling = NullValueHandling.Ignore)] + public string ChangeType { 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; } - } + [JsonProperty("meeting", NullValueHandling = NullValueHandling.Ignore)] + public Meeting Meeting { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs index 6bd04a74..1fad0641 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs @@ -12,12 +12,19 @@ namespace PepperDash.Essentials.AppServer.Messengers { private readonly IHumiditySensor device; + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// public IHumiditySensorMessenger(string key, IHumiditySensor device, string messagePath) : base(key, messagePath, device as IKeyName) { this.device = device; } + /// protected override void RegisterActions() { base.RegisterActions(); @@ -52,4 +59,4 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("humidity")] public string Humidity { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs index 03bfc80f..6ddb671d 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs @@ -14,11 +14,18 @@ namespace PepperDash.Essentials.AppServer.Messengers { private ILevelControls levelControlsDevice; + /// + /// Create an instance of the class. + /// + /// + /// + /// public ILevelControlsMessenger(string key, string messagePath, ILevelControls device) : base(key, messagePath, device as IKeyName) { levelControlsDevice = device; } + /// protected override void RegisterActions() { base.RegisterActions(); @@ -87,6 +94,9 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class LevelControlStateMessage : DeviceStateMessageBase { + /// + /// Gets or sets the Levels + /// [JsonProperty("levelControls")] public Dictionary Levels { get; set; } } @@ -96,13 +106,16 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class LevelControlRequestMessage { - [JsonProperty("key")] /// /// Gets or sets the Key /// + [JsonProperty("key")] public string Key { get; set; } + /// + /// Represents a Volume + /// [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] public ushort? Level { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs index ec718919..3ea457d2 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs @@ -16,11 +16,20 @@ namespace PepperDash.Essentials.AppServer.Messengers public class IMatrixRoutingMessenger : MessengerBase { private readonly IMatrixRouting matrixDevice; - public IMatrixRoutingMessenger(string key, string messagePath, IMatrixRouting device) : base(key, messagePath, device as IKeyName) + + + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + public IMatrixRoutingMessenger(string key, string messagePath, IMatrixRouting device) : base(key, messagePath, device as IKeyName) { matrixDevice = device; } + /// protected override void RegisterActions() { base.RegisterActions(); @@ -99,9 +108,15 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class MatrixStateMessage : DeviceStateMessageBase { + /// + /// Gets or sets the Outputs + /// [JsonProperty("outputs")] public Dictionary Outputs; + /// + /// Gets or sets the Inputs + /// [JsonProperty("inputs")] public Dictionary Inputs; } @@ -109,33 +124,60 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// Represents a RoutingInput /// - public class RoutingInput + public class RoutingInput : IKeyName { private IRoutingInputSlot _input; + /// + /// Gets the TxDeviceKey of the input slot + /// [JsonProperty("txDeviceKey", NullValueHandling = NullValueHandling.Ignore)] public string TxDeviceKey => _input?.TxDeviceKey; + /// + /// Gets the SlotNumber of the input slot + /// + /// [JsonProperty("slotNumber", NullValueHandling = NullValueHandling.Ignore)] public int? SlotNumber => _input?.SlotNumber; + /// + /// Gets the SupportedSignalTypes of the input slot + /// [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] [JsonProperty("supportedSignalTypes", NullValueHandling = NullValueHandling.Ignore)] public eRoutingSignalType? SupportedSignalTypes => _input?.SupportedSignalTypes; + /// + /// Gets the Name of the input slot + /// [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name => _input?.Name; + /// + /// Gets the IsOnline of the input slot + /// + /// [JsonProperty("isOnline", NullValueHandling = NullValueHandling.Ignore)] public bool? IsOnline => _input?.IsOnline.BoolValue; - [JsonProperty("videoSyncDetected", NullValueHandling = NullValueHandling.Ignore)] + /// + /// Gets the VideoSyncDetected of the input slot + /// + [JsonProperty("videoSyncDetected", NullValueHandling = NullValueHandling.Ignore)] public bool? VideoSyncDetected => _input?.VideoSyncDetected; + /// + /// Gets the Key of the input slot + /// [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] public string Key => _input?.Key; + /// + /// Initializes a new instance of the class. + /// + /// public RoutingInput(IRoutingInputSlot input) { _input = input; @@ -145,32 +187,55 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// Represents a RoutingOutput /// - public class RoutingOutput + public class RoutingOutput : IKeyName { private IRoutingOutputSlot _output; - + /// + /// Initializes a new instance of the class. + /// + /// public RoutingOutput(IRoutingOutputSlot output) { _output = output; } + /// + /// Gets the RxDeviceKey of the output slot + /// [JsonProperty("rxDeviceKey")] public string RxDeviceKey => _output.RxDeviceKey; + /// + /// Gets the CurrentRoutes of the output slot + /// [JsonProperty("currentRoutes")] public Dictionary CurrentRoutes => _output.CurrentRoutes.ToDictionary(kvp => kvp.Key.ToString(), kvp => new RoutingInput(kvp.Value)); + /// + /// Gets the SlotNumber of the output slot + /// [JsonProperty("slotNumber")] public int SlotNumber => _output.SlotNumber; + /// + /// Gets the SupportedSignalTypes of the output slot + /// [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] [JsonProperty("supportedSignalTypes")] public eRoutingSignalType SupportedSignalTypes => _output.SupportedSignalTypes; + + /// + /// Gets the Name of the output slot + /// [JsonProperty("name")] public string Name => _output.Name; + + /// + /// Gets the Key of the output slot + /// [JsonProperty("key")] public string Key => _output.Key; } @@ -180,22 +245,23 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class MatrixRouteRequest { - [JsonProperty("outputKey")] /// /// Gets or sets the OutputKey /// + [JsonProperty("outputKey")] public string OutputKey { get; set; } - [JsonProperty("inputKey")] /// /// Gets or sets the InputKey /// + [JsonProperty("inputKey")] public string InputKey { get; set; } - [JsonProperty("routeType")] /// /// Gets or sets the RouteType /// + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + [JsonProperty("routeType")] public eRoutingSignalType RouteType { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs index f63b4834..a02f0f99 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs @@ -101,4 +101,4 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] public eScreenLiftControlType Type { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs index 8e2f8f3e..df1315a3 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs @@ -158,4 +158,4 @@ namespace PepperDash.Essentials.AppServer.Messengers public TKey CurrentItem { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs index 516e77c6..f3b21d7b 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs @@ -12,12 +12,19 @@ namespace PepperDash.Essentials.AppServer.Messengers { private readonly IShutdownPromptTimer _room; + /// + /// Create an instance of the class. + /// + /// + /// + /// 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)); @@ -104,4 +111,4 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("shutdownPromptSeconds")] public int ShutdownPromptSeconds { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs index 98223188..ec4acfd8 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs @@ -13,12 +13,20 @@ namespace PepperDash.Essentials.AppServer.Messengers private readonly ISwitchedOutput device; + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// public ISwitchedOutputMessenger(string key, ISwitchedOutput device, string messagePath) : base(key, messagePath, device as IKeyName) { this.device = device; } + + /// protected override void RegisterActions() { base.RegisterActions(); @@ -66,4 +74,4 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("isOn")] public bool IsOn { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs index 283ef0c8..c511c68c 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs @@ -11,12 +11,19 @@ namespace PepperDash.Essentials.AppServer.Messengers { private readonly ITechPassword _room; + /// + /// Constructor for ITechPasswordMessenger + /// + /// + /// + /// public ITechPasswordMessenger(string key, string messagePath, ITechPassword room) : base(key, messagePath, room as IKeyName) { _room = room; } + /// protected override void RegisterActions() { @@ -71,6 +78,9 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class ITechPasswordStateMessage : DeviceStateMessageBase { + /// + /// Gets or sets the TechPasswordLength + /// [JsonProperty("techPasswordLength", NullValueHandling = NullValueHandling.Ignore)] public int? TechPasswordLength { get; set; } } @@ -80,23 +90,26 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class ITechPasswordEventMessage : DeviceEventMessageBase { + /// + /// Gets or sets the IsValid + /// [JsonProperty("isValid", NullValueHandling = NullValueHandling.Ignore)] public bool? IsValid { get; set; } } internal class SetTechPasswordContent { - [JsonProperty("oldPassword")] /// /// Gets or sets the OldPassword /// + [JsonProperty("oldPassword")] public string OldPassword { get; set; } - [JsonProperty("newPassword")] /// /// Gets or sets the NewPassword /// + [JsonProperty("newPassword")] public string NewPassword { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs index 5963bba5..e455ed81 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs @@ -12,12 +12,20 @@ namespace PepperDash.Essentials.AppServer.Messengers { private readonly ITemperatureSensor device; + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// public ITemperatureSensorMessenger(string key, ITemperatureSensor device, string messagePath) : base(key, messagePath, device as IKeyName) { this.device = device; } + + /// protected override void RegisterActions() { base.RegisterActions(); @@ -72,4 +80,4 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("temperatureInCelsius")] public bool TemperatureInCelsius { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs index 71c6349f..34f2db13 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs @@ -13,6 +13,13 @@ namespace PepperDash.Essentials.AppServer.Messengers { private ILightingScenes lightingScenesDevice; + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// public ILightingScenesMessenger(string key, ILightingScenes device, string messagePath) : base(key, messagePath, device as IKeyName) { @@ -31,6 +38,7 @@ namespace PepperDash.Essentials.AppServer.Messengers PostStatusMessage(state); } + /// protected override void RegisterActions() { base.RegisterActions(); diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs index 3031f4ba..e634631a 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs @@ -403,4 +403,4 @@ namespace PepperDash.Essentials.AppServer.Messengers } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs index b076566b..17eb2656 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs @@ -119,4 +119,4 @@ namespace PepperDash.Essentials.AppServer.Messengers timerHandler(deviceKey, action); } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs index 2e10d0f3..8969dcd3 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs @@ -6,87 +6,92 @@ using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Room.Config; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +/// +/// Represents a RoomEventScheduleMessenger +/// +public class RoomEventScheduleMessenger : MessengerBase +{ + private readonly IRoomEventSchedule _room; + + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + 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 { /// - /// Represents a RoomEventScheduleMessenger + /// Gets or sets the ScheduleEvents /// - 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; } - } -} \ No newline at end of file + [JsonProperty("scheduleEvents")] + public List ScheduleEvents { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs index 5492cc2b..dc5cbe6a 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs @@ -12,12 +12,19 @@ namespace PepperDash.Essentials.AppServer.Messengers { private readonly IShadesOpenCloseStop device; + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// public IShadesOpenCloseStopMessenger(string key, IShadesOpenCloseStop shades, string messagePath) : base(key, messagePath, shades as IKeyName) { device = shades; } + /// protected override void RegisterActions() { base.RegisterActions(); @@ -102,9 +109,16 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("middleButtonLabel", NullValueHandling = NullValueHandling.Ignore)] public string MiddleButtonLabel { get; set; } + /// + /// Gets or sets the IsOpen + /// [JsonProperty("isOpen", NullValueHandling = NullValueHandling.Ignore)] public bool? IsOpen { get; set; } + + /// + /// Gets or sets the IsClosed + /// [JsonProperty("isClosed", NullValueHandling = NullValueHandling.Ignore)] public bool? IsClosed { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs index 63869ae0..857bfa0f 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs @@ -82,6 +82,7 @@ namespace PepperDash.Essentials.AppServer.Messengers )); } + /// protected override void RegisterActions() { AddAction("/fullStatus", (id, content) => SendFullStatusMessage(id)); diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs index 5147da4d..77a7cc95 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs @@ -12,6 +12,12 @@ namespace PepperDash.Essentials.AppServer.Messengers { private readonly TwoWayDisplayBase _display; + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// public TwoWayDisplayBaseMessenger(string key, string messagePath, TwoWayDisplayBase display) : base(key, messagePath, display) { @@ -34,6 +40,7 @@ namespace PepperDash.Essentials.AppServer.Messengers PostStatusMessage(messageObj, id); } + /// protected override void RegisterActions() { base.RegisterActions(); diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlMessage.cs b/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlMessage.cs index a7a072ba..abb6de5e 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlMessage.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlMessage.cs @@ -9,22 +9,22 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class MobileControlMessage : IMobileControlMessage { - [JsonProperty("type")] /// /// Gets or sets the Type /// + [JsonProperty("type")] public string Type { get; set; } - [JsonProperty("clientId")] /// /// Gets or sets the ClientId /// + [JsonProperty("clientId")] public string ClientId { get; set; } - [JsonProperty("content")] /// /// Gets or sets the Content /// + [JsonProperty("content")] public JToken Content { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlSimpleContent.cs b/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlSimpleContent.cs index 71972fc3..96d80f87 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlSimpleContent.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlSimpleContent.cs @@ -1,16 +1,18 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials.AppServer +namespace PepperDash.Essentials.AppServer; + + +/// +/// Represents a MobileControlSimpleContent +/// +public class MobileControlSimpleContent { /// - /// Represents a MobileControlSimpleContent + /// Gets or sets the Value /// - public class MobileControlSimpleContent - { - [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] - /// - /// Gets or sets the Value - /// - public T Value { get; set; } - } + [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] + + public T Value { get; set; } } + diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLVtcJoinMap.cs b/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLVtcJoinMap.cs index b53424bd..67ed8877 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLVtcJoinMap.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLVtcJoinMap.cs @@ -1,3 +1,4 @@ + using PepperDash.Essentials.Core; @@ -553,4 +554,4 @@ namespace PepperDash.Essentials.AppServer { } } -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs b/src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs index 7ba130bc..4636f68a 100644 --- a/src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs +++ b/src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs @@ -1,37 +1,38 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + + +/// +/// Represents a AuthorizationResponse +/// +public class AuthorizationResponse { - /// - /// 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 + /// Gets or sets the Authorized /// - public class AuthorizationRequest - { + [JsonProperty("authorized")] + public bool Authorized { get; set; } - /// - /// Gets or sets the GrantCode - /// - [JsonProperty("grantCode")] - public string GrantCode { 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; } +} + diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlAction.cs b/src/PepperDash.Essentials.MobileControl/MobileControlAction.cs index 16a9bd40..1136c3c1 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlAction.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlAction.cs @@ -2,32 +2,33 @@ using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + + +/// +/// Represents a MobileControlAction +/// +public class MobileControlAction : IMobileControlAction { /// - /// Represents a MobileControlAction + /// Gets the Messenger /// - public class MobileControlAction : IMobileControlAction + 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) { - /// - /// 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; - } + Messenger = messenger; + Action = handler; } } + diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlDeviceFactory.cs b/src/PepperDash.Essentials.MobileControl/MobileControlDeviceFactory.cs index 6147b14e..c08b9c9f 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlDeviceFactory.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlDeviceFactory.cs @@ -5,34 +5,26 @@ 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" }; - } +namespace PepperDash.Essentials; - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) +public class MobileControlDeviceFactory : EssentialsDeviceFactory +{ + public MobileControlDeviceFactory() + { + TypeNames = new List { "appserver", "mobilecontrol", "webserver" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + try { - 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; - } + 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; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs b/src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs index d0415287..a0b5ebb8 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs @@ -1,74 +1,75 @@ using System.Collections.Generic; using Newtonsoft.Json; +using PepperDash.Essentials; using PepperDash.Essentials.Core.Config; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + +/// +/// Configuration class for sending data to Mobile Control Edge or a client using the Direct Server +/// +public class MobileControlEssentialsConfig : EssentialsConfig { /// - /// Configuration class for sending data to Mobile Control Edge or a client using the Direct Server + /// Current versions for the system /// - 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(); - } - } + [JsonProperty("runtimeInfo")] + public MobileControlRuntimeInfo RuntimeInfo { get; set; } /// - /// Represents a MobileControlRuntimeInfo + /// Create Configuration for Mobile Control. Used as part of the data sent to a client /// - public class MobileControlRuntimeInfo + /// 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; - /// - /// Gets or sets the PluginVersion - /// - [JsonProperty("pluginVersion")] - public string PluginVersion { get; set; } + if (Info == null) + Info = new InfoConfig(); - /// - /// 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; } + RuntimeInfo = new MobileControlRuntimeInfo(); } -} \ No newline at end of file + +} + +/// +/// 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; } +} diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs index 3adcaf87..f0f8caa1 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs @@ -2510,4 +2510,4 @@ namespace PepperDash.Essentials CrestronConsole.ConsoleCommandResponse("Usage: mobilehttprequest:N get/post url\r"); } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlBridgeBase.cs b/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlBridgeBase.cs index 634255fe..3e2707a8 100644 --- a/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlBridgeBase.cs +++ b/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlBridgeBase.cs @@ -5,193 +5,126 @@ using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -namespace PepperDash.Essentials.RoomBridges +namespace PepperDash.Essentials.RoomBridges; + +/// +/// +/// +public abstract class MobileControlBridgeBase : MessengerBase, IMobileControlRoomMessenger { - /// - /// Base class for a Mobile Control Bridge that's used to control a room - /// - public abstract class MobileControlBridgeBase : MessengerBase, IMobileControlRoomMessenger + public event EventHandler UserCodeChanged; + + public event EventHandler UserPromptedForCode; + + public event EventHandler ClientJoined; + + public event EventHandler AppUrlChanged; + + public IMobileControl Parent { get; private set; } + + public string AppUrl { get; private set; } + public string UserCode { get; private set; } + + public string QrCodeUrl { get; protected set; } + + public string QrCodeChecksum { get; protected set; } + + public string McServerUrl { get; private set; } + + public abstract string RoomName { get; } + + public abstract string RoomKey { get; } + + protected MobileControlBridgeBase(string key, string messagePath) + : base(key, messagePath) { - /// - /// 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; + protected MobileControlBridgeBase(string key, string messagePath, IKeyName device) + : base(key, messagePath, device) + { + } - /// - /// Triggered when a client joins to control this room - /// - public event EventHandler ClientJoined; + /// + /// Set the parent. Does nothing else. Override to add functionality such + /// as adding actions to parent + /// + /// + public virtual void AddParent(IMobileControl parent) + { + Parent = parent; - /// - /// Triggered when the App URL for this room changes - /// - public event EventHandler AppUrlChanged; + McServerUrl = Parent.ClientAppUrl; + } - /// - /// 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) + /// + /// Sets the UserCode on the bridge object. Called from controller. A changed code will + /// fire method UserCodeChange. Override that to handle changes + /// + /// + public void SetUserCode(string code) + { + var changed = UserCode != code; + UserCode = code; + if (changed) { - } - - /// - /// 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()); + 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); + } + + 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(); + } + + protected void OnUserCodeChanged() + { + UserCodeChanged?.Invoke(this, new EventArgs()); + } + + protected void OnUserPromptedForCode() + { + UserPromptedForCode?.Invoke(this, new EventArgs()); + } + + protected void OnClientJoined() + { + ClientJoined?.Invoke(this, new EventArgs()); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/Services/MobileControlApiService.cs b/src/PepperDash.Essentials.MobileControl/Services/MobileControlApiService.cs index 508fb776..f3b02bb6 100644 --- a/src/PepperDash.Essentials.MobileControl/Services/MobileControlApiService.cs +++ b/src/PepperDash.Essentials.MobileControl/Services/MobileControlApiService.cs @@ -3,89 +3,74 @@ using System.Net.Http; using System.Threading.Tasks; using PepperDash.Core; -namespace PepperDash.Essentials.Services +namespace PepperDash.Essentials.Services; + + +public class MobileControlApiService { + private readonly HttpClient _client; - /// - /// Service for interacting with a Mobile Control Edge server instance - /// - public class MobileControlApiService + public MobileControlApiService(string apiUrl) { - private readonly HttpClient _client; - - /// - /// Create an instance of the class. - /// - /// Mobile Control Edge API URL - public MobileControlApiService(string apiUrl) + var handler = new HttpClientHandler { - var handler = new HttpClientHandler + AllowAutoRedirect = false, + ServerCertificateCustomValidationCallback = (req, cert, certChain, errors) => true + }; + + _client = new HttpClient(handler); + } + + 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 { - AllowAutoRedirect = false, - ServerCertificateCustomValidationCallback = (req, cert, certChain, errors) => true + Authorized = response.StatusCode == System.Net.HttpStatusCode.OK }; - _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 + if (authResponse.Authorized) { - var request = new HttpRequestMessage(HttpMethod.Get, $"{apiUrl}/system/{systemUuid}/authorize?grantCode={grantCode}"); + return authResponse; + } - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Sending authorization request to {host}", null, request.RequestUri); + if (response.StatusCode == System.Net.HttpStatusCode.Moved) + { + var location = response.Headers.Location; - 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; - } + authResponse.Reason = $"ERROR: Mobile Control API has moved. Please adjust configuration to \"{location}\""; return authResponse; } - catch (Exception ex) + + var responseString = await response.Content.ReadAsStringAsync(); + + switch (responseString) { - Debug.LogMessage(ex, "Error authorizing with Mobile Control"); - return new AuthorizationResponse { Authorized = false, Reason = ex.Message }; + 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 }; } } } diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITheme.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITheme.cs index c7efbf4c..827331db 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITheme.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITheme.cs @@ -1,21 +1,21 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Touchpanel +namespace PepperDash.Essentials.Touchpanel; + +/// +/// Defines the contract for ITheme +/// +public interface ITheme : IKeyed { /// - /// Defines the contract for ITheme + /// Current theme /// - public interface ITheme : IKeyed - { - /// - /// Current theme - /// - string Theme { get; } + string Theme { get; } - /// - /// Set the theme with the given value - /// - /// The theme to set - void UpdateTheme(string theme); - } + /// + /// Set the theme with the given value + /// + /// The theme to set + void UpdateTheme(string theme); } + diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControl.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControl.cs index 055ad80c..35a7d37e 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControl.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControl.cs @@ -1,52 +1,53 @@ using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Touchpanel +namespace PepperDash.Essentials.Touchpanel; + + +/// +/// Defines the contract for ITswAppControl +/// +public interface ITswAppControl : IKeyed { /// - /// Defines the contract for ITswAppControl + /// Updates when the Zoom Room Control Application opens or closes /// - 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(); - } + BoolFeedback AppOpenFeedback { get; } /// - /// Defines the contract for ITswZoomControl + /// Hide the Zoom App and show the User Control Application /// - public interface ITswZoomControl : IKeyed - { - /// - /// Updates when Zoom has an incoming call - /// - BoolFeedback ZoomIncomingCallFeedback { get; } + void HideOpenApp(); - /// - /// Updates when Zoom is in a call - /// - BoolFeedback ZoomInCallFeedback { get; } + /// + /// Close the Zoom App and show the User Control Application + /// + void CloseOpenApp(); - /// - /// End a Zoom Call - /// - void EndZoomCall(); - } + /// + /// 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(); +} + diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControlMessenger.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControlMessenger.cs index acfcab2a..a4e7739e 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControlMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControlMessenger.cs @@ -72,4 +72,4 @@ namespace PepperDash.Essentials.Touchpanel [JsonProperty("appOpen", NullValueHandling = NullValueHandling.Ignore)] public bool? AppOpen { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswZoomControlMessenger.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswZoomControlMessenger.cs index bbf4030e..61a3ebbd 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswZoomControlMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswZoomControlMessenger.cs @@ -92,4 +92,4 @@ namespace PepperDash.Essentials.Touchpanel [JsonProperty("incomingCall", NullValueHandling = NullValueHandling.Ignore)] public bool? IncomingCall { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs index 5830782d..30f4542b 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs @@ -818,4 +818,4 @@ namespace PepperDash.Essentials.Touchpanel } } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs index 8156834b..cf022c16 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs @@ -1,39 +1,40 @@ -using Newtonsoft.Json; + +using Newtonsoft.Json; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Touchpanel +namespace PepperDash.Essentials.Touchpanel; + +/// +/// Represents a MobileControlTouchpanelProperties +/// +public class MobileControlTouchpanelProperties : CrestronTouchpanelPropertiesConfig { + /// - /// Represents a MobileControlTouchpanelProperties + /// Gets or sets the UseDirectServer /// - public class MobileControlTouchpanelProperties : CrestronTouchpanelPropertiesConfig - { - - /// - /// Gets or sets the UseDirectServer - /// - [JsonProperty("useDirectServer")] - public bool UseDirectServer { get; set; } = false; + [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 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 ButtonToolbarTimoutInS + /// + [JsonProperty("buttonToolbarTimeoutInS")] + public ushort ButtonToolbarTimoutInS { get; set; } = 0; - /// - /// Gets or sets the Theme - /// - [JsonProperty("theme")] - public string Theme { get; set; } = "light"; - } -} \ No newline at end of file + /// + /// Gets or sets the Theme + /// + [JsonProperty("theme")] + public string Theme { get; set; } = "light"; +} + diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs index 35d85442..cecd613e 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs @@ -57,4 +57,4 @@ namespace PepperDash.Essentials.Touchpanel [JsonProperty("theme")] public string Theme { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs b/src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs index ce31f766..a7f4e893 100644 --- a/src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs +++ b/src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs @@ -1,24 +1,24 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + +/// +/// Represents a UserCodeChangedContent +/// +public class UserCodeChangedContent { + /// - /// Represents a UserCodeChangedContent + /// Gets or sets the UserCode /// - public class UserCodeChangedContent - { - - /// - /// Gets or sets the UserCode - /// - [JsonProperty("userCode")] - public string UserCode { get; set; } + [JsonProperty("userCode")] + public string UserCode { get; set; } - /// - /// Gets or sets the QrChecksum - /// - [JsonProperty("qrChecksum", NullValueHandling = NullValueHandling.Include)] - public string QrChecksum { get; set; } - } + /// + /// Gets or sets the QrChecksum + /// + [JsonProperty("qrChecksum", NullValueHandling = NullValueHandling.Include)] + public string QrChecksum { get; set; } } + diff --git a/src/PepperDash.Essentials.MobileControl/Volumes.cs b/src/PepperDash.Essentials.MobileControl/Volumes.cs index 44febbfc..2d95a675 100644 --- a/src/PepperDash.Essentials.MobileControl/Volumes.cs +++ b/src/PepperDash.Essentials.MobileControl/Volumes.cs @@ -1,137 +1,137 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace PepperDash.Essentials +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 { /// - /// Represents a Volumes + /// Gets or sets the Key /// - public class Volumes + [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) { - - /// - /// 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; } + Level = level; + Muted = muted; + Label = label; + HasMute = hasMute; + MuteIcon = muteIcon; } /// - /// Represents a Volume + /// Create an instance of the class /// - public class Volume + /// The key for this volume object + /// The level for this volume object + public Volume(string key, int level) + : this(key) { - /// - /// 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; - } + Level = level; } -} \ No newline at end of file + + /// + /// 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; + } +} diff --git a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs index 1c204e8e..5bf7be4b 100644 --- a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs +++ b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs @@ -81,4 +81,4 @@ namespace PepperDash.Essentials.WebApiHandlers [JsonProperty("path")] public string Path { get; set; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileAuthRequestHandler.cs b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileAuthRequestHandler.cs index 5d9e9766..850a3e6a 100644 --- a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileAuthRequestHandler.cs +++ b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileAuthRequestHandler.cs @@ -68,4 +68,4 @@ namespace PepperDash.Essentials.WebApiHandlers } } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs index 676fd3c8..551a9b4d 100644 --- a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs +++ b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs @@ -284,4 +284,4 @@ namespace PepperDash.Essentials.WebApiHandlers this.client = client; } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs index 2f972ddf..2a7ed8c7 100644 --- a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs +++ b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs @@ -1,3 +1,4 @@ + using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs index 210dc577..f1af6bbf 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs @@ -1,26 +1,29 @@ -using System.Collections.Concurrent; +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 PepperDash.Essentials.Core; -using System.Collections.Generic; -using System; -using System.Net.Http; using Crestron.SimplSharp; -using System.Linq; -using PepperDash.Core.Logging; -using PepperDash.Essentials.Core.Web; 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; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using System.IO; -using Newtonsoft.Json; -using PepperDash.Core; -using Serilog.Events; -using PepperDash.Essentials.RoomBridges; + namespace PepperDash.Essentials.WebSocketServer { @@ -48,7 +51,7 @@ namespace PepperDash.Essentials.WebSocketServer private HttpServer _server; /// - /// Gets the WebSocketServer instance + /// Gets the HttpServer instance /// public HttpServer Server => _server; @@ -264,35 +267,34 @@ namespace PepperDash.Essentials.WebSocketServer { base.Initialize(); - _server = new HttpServer(Port, false); - - - - _server.OnGet += (sender, e) => Server_OnGet(sender, e); - - _server.OnOptions += (sender, e) => Server_OnOptions(sender, e); - - if (_parent.Config.DirectServer.Logging.EnableRemoteLogging) - { - _server.OnPost += (sender, e) => Server_OnPost(sender, e); - } + ServerSslConfiguration sslConfig = null; if (_parent.Config.DirectServer.Secure) { this.LogInformation("Adding SSL Configuration to server"); - - ServerSslConfiguration sslConfig = null; - sslConfig = new ServerSslConfiguration(new X509Certificate2($"\\user\\{certificateName}.pfx", certificatePassword)) { ClientCertificateRequired = false, CheckCertificateRevocation = false, EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 }; + } + _server = new HttpServer(Port, false); + if (sslConfig != null) + { _server.SslConfiguration.ServerCertificate = sslConfig.ServerCertificate; } + _server.OnGet += Server_OnGet; + + _server.OnOptions += Server_OnOptions; + + if (_parent.Config.DirectServer.Logging.EnableRemoteLogging) + { + _server.OnPost += Server_OnPost; + } + _server.Log.Output = (data, message) => Utilities.ConvertWebsocketLog(data, message, this); // setting to trace to allow logging level to be controlled by appdebug @@ -1463,4 +1465,4 @@ namespace PepperDash.Essentials.WebSocketServer } } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs index 607323ba..99e25634 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs @@ -267,4 +267,4 @@ namespace PepperDash.Essentials.WebSocketServer this.LogDebug(e.Exception, "Stack Trace"); } } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/WebSocketServerSecretProvider.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/WebSocketServerSecretProvider.cs index 3dd67bd8..566ed22a 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/WebSocketServerSecretProvider.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/WebSocketServerSecretProvider.cs @@ -52,4 +52,4 @@ namespace PepperDash.Essentials.WebSocketServer } -} +} \ No newline at end of file diff --git a/src/PepperDash.Essentials/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/src/PepperDash.Essentials/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index 9c78c4aa..b6533089 100644 --- a/src/PepperDash.Essentials/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/src/PepperDash.Essentials/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -3,38 +3,37 @@ using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; -namespace PepperDash.Essentials.Fusion +namespace PepperDash.Essentials.Fusion; + +public class EssentialsHuddleSpaceFusionSystemControllerBase { - public class EssentialsHuddleSpaceFusionSystemControllerBase + private ClientWebSocket _webSocket; + + public EssentialsHuddleSpaceFusionSystemControllerBase() { - private ClientWebSocket _webSocket; + _webSocket = new ClientWebSocket(); + } - public EssentialsHuddleSpaceFusionSystemControllerBase() - { - _webSocket = new ClientWebSocket(); - } + public async Task ConnectAsync(Uri uri) + { + await _webSocket.ConnectAsync(uri, CancellationToken.None); + } - public async Task ConnectAsync(Uri uri) - { - await _webSocket.ConnectAsync(uri, CancellationToken.None); - } + public async Task SendAsync(string message) + { + var buffer = System.Text.Encoding.UTF8.GetBytes(message); + await _webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None); + } - public async Task SendAsync(string message) - { - var buffer = System.Text.Encoding.UTF8.GetBytes(message); - await _webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None); - } + public async Task ReceiveAsync() + { + var buffer = new byte[1024]; + var result = await _webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + return System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count); + } - public async Task ReceiveAsync() - { - var buffer = new byte[1024]; - var result = await _webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); - return System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count); - } - - public async Task CloseAsync() - { - await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); - } + public async Task CloseAsync() + { + await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); } } diff --git a/src/PepperDash.Essentials/HttpLogoServer.cs b/src/PepperDash.Essentials/HttpLogoServer.cs index d5d133e6..174ebd7e 100644 --- a/src/PepperDash.Essentials/HttpLogoServer.cs +++ b/src/PepperDash.Essentials/HttpLogoServer.cs @@ -7,127 +7,117 @@ using Crestron.SimplSharp.Net.Http; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + +public class HttpLogoServer { /// - /// HTTP server for serving logo images and files + /// /// - public class HttpLogoServer + readonly HttpServer _server; + + /// + /// + /// + readonly string _fileDirectory; + + /// + /// + /// + public static Dictionary ExtensionContentTypes; + + /// + /// + /// + /// + /// + public HttpLogoServer(int port, string directory) { - /// - /// 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 + ExtensionContentTypes = new Dictionary { - //{ ".css", "text/css" }, - //{ ".htm", "text/html" }, - //{ ".html", "text/html" }, + //{ ".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" }, + //{ ".js", "application/javascript" }, + //{ ".json", "application/json" }, + //{ ".map", "application/x-navimap" }, { ".pdf", "application/pdf" }, { ".png", "image/png" }, - //{ ".txt", "text/plain" }, + //{ ".txt", "text/plain" }, }; - _server = new HttpServer {Port = port}; - _fileDirectory = directory; - _server.OnHttpRequest += Server_OnHttpRequest; - _server.Open(); + _server = new HttpServer {Port = port}; + _fileDirectory = directory; + _server.OnHttpRequest += Server_OnHttpRequest; + _server.Open(); - CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; - } + 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) + /// + /// + /// + 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 { - 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)) { - if (File.Exists(_fileDirectory + path)) - { - var filePath = path.Replace('/', '\\'); - var localPath = string.Format(@"{0}{1}", _fileDirectory, filePath); + 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; - } + 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: '{file:l}' does not exist", _fileDirectory + path); - args.Response.ContentString = string.Format("Not found: '{0}'", _fileDirectory + path); + 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; } } - catch (Exception ex) + else { - 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"); + 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; } } - - /// - /// Handles program status events and closes the server when the program is stopping - /// - /// The program status event type - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + catch (Exception ex) { - if (programEventType == eProgramStatusEventType.Stopping) - _server.Close(); - } + Debug.LogMessage(LogEventLevel.Error, "Exception getting file: {exception}", ex.Message, ex.StackTrace); + Debug.LogMessage(LogEventLevel.Verbose, "Stack Trace: {stackTrace}", ex.StackTrace); - /// - /// 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; + args.Response.Code = 400; + args.Response.ContentString = string.Format("invalid request"); } } + + /// + /// + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping) + _server.Close(); + } + + /// + /// + /// + /// + /// + public static string GetContentType(string extension) + { + var type = ExtensionContentTypes.ContainsKey(extension) ? ExtensionContentTypes[extension] : "text/plain"; + return type; + } } \ No newline at end of file