Compare commits

..

289 Commits

Author SHA1 Message Date
Andrew Welker
0c4aec14d1 fix: use .NET timers instead of CTimer 2025-12-29 11:53:52 -06:00
Andrew Welker
7d3f871460 Merge branch 'copilot/featureadd-raise-lower-time' into mc-connection-issues 2025-12-29 09:03:09 -06:00
Andrew Welker
78c9381108 fix: add clientId as qp for websocket for MC 2025-12-29 08:57:52 -06:00
Erik Meyer
a7ff2e8903 fix: move isInUpPosition to momvement complete method, remove conditionlal logic on raise/lower commands 2025-12-27 17:09:56 -06:00
copilot-swe-agent[bot]
ae0b2fe086 Refactor timer disposal and improve code readability
Co-authored-by: erikdred <88980320+erikdred@users.noreply.github.com>
2025-12-27 20:17:59 +00:00
copilot-swe-agent[bot]
bd11c827da Split movement time into separate raise/lower times and remove timing from latched mode
Co-authored-by: erikdred <88980320+erikdred@users.noreply.github.com>
2025-12-27 20:14:39 +00:00
copilot-swe-agent[bot]
7ea1efbabf Add raise/lower movement time configuration and banked command support
Co-authored-by: erikdred <88980320+erikdred@users.noreply.github.com>
2025-12-27 20:09:31 +00:00
copilot-swe-agent[bot]
9d6aaa2a0e Initial plan 2025-12-27 20:02:52 +00:00
Andrew Welker
53e7a30224 fix: handle threading issues for concurrent clients joining 2025-12-26 12:34:31 -06:00
Neil Dorin
39c1f60a4d Merge pull request #1370 from PepperDash/udp-eisc 2025-12-23 12:10:37 -05:00
Andrew Welker
2cc37a4e40 fix: ExecuteJoinAction now uses the correct Sig collections 2025-12-23 11:06:52 -06:00
Andrew Welker
076e5dfa9d chore: update comments, debug methods, and mark some things obsolete 2025-12-23 10:25:53 -06:00
Andrew Welker
092896bb25 fix: support for legacy UDP EISC 2025-12-23 09:57:49 -06:00
Neil Dorin
7c8f0586e6 Merge pull request #1369 from PepperDash/volume-messenger-issue 2025-12-16 17:15:46 -05:00
Andrew Welker
c5b0872a4c fix: DeviceVolumeMessenger only sends rawValue when device implements it 2025-12-16 15:41:33 -06:00
Andrew Welker
a7b88ec38d Merge pull request #1368 from PepperDash/generic-sink
generic sink
2025-12-16 11:09:40 -05:00
Andrew Welker
210b398a13 fix: implement PR Review suggestions 2025-12-16 10:04:01 -06:00
Nick Genovese
bce1e3610e fix: copy dictionaries
- fixed multiple enumeration exception
2025-12-10 16:58:41 -06:00
Andrew Welker
6a33e7c99d fix: initialize current sources dictionaries 2025-12-05 16:26:08 -06:00
Andrew Welker
2048e3f65d fix: GenericSink implements ICurrentSources 2025-12-05 16:26:02 -06:00
Neil Dorin
81df2738de Merge pull request #1363 from PepperDash/feature/add-on-off-dsp-preset-keys-to-room-config
feat: Add on/off dsp keys to EssentialsAvRoomPropertiesConfig
2025-11-26 18:00:18 -05:00
Neil Dorin
08fbec416f Update src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-26 15:53:45 -07:00
Neil Dorin
7594b22096 Update src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-26 15:53:39 -07:00
Neil Dorin
d1babf6b9b Update src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-26 15:53:31 -07:00
Neil Dorin
2187c9fb0d Update src/PepperDash.Essentials.Core/Devices/SourceListItem.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-26 15:53:22 -07:00
Neil Dorin
a5e6059160 Update src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-26 15:53:14 -07:00
Neil Dorin
9ef4aedcce Update src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-26 15:53:07 -07:00
Neil Dorin
f7c7160bf0 feat: Add on/off dsp keys to EssentialsAvRoomPropertiesConfig
clean up XML comments and improve property definitions in EssentialsRoomConfig
2025-11-26 15:48:14 -07:00
Neil Dorin
dbf5740841 Merge pull request #1362 from PepperDash/feature/add-IHasFeedback-to-IEssentialsRoomFusionController
fix: ensure proper disposal of help request timeout timer and improve…
2025-11-26 13:28:55 -05:00
Neil Dorin
c07e099a79 feat: add logging for help request timeout events in IEssentialsRoomFusionController 2025-11-26 11:10:21 -07:00
Neil Dorin
06cb508f3a Update src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-26 11:09:07 -07:00
Neil Dorin
e93b5b34cc Update src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-26 11:09:02 -07:00
Neil Dorin
4f5d4ef87a fix: ensure proper disposal of help request timeout timer and improve logging 2025-11-26 11:02:31 -07:00
Andrew Welker
636da8cc8c Merge pull request #1361 from PepperDash/feature/add-IHasFeedback-to-IEssentialsRoomFusionController
feat: add help request timeout functionality to IEssentialsRoomFusion…
2025-11-26 12:34:48 -05:00
Neil Dorin
5de1e2d7bb feat: add help request timeout functionality to IEssentialsRoomFusionController 2025-11-26 10:26:41 -07:00
Andrew Welker
03bbb84894 Merge pull request #1359 from PepperDash/feature/add-IHasFeedback-to-IEssentialsRoomFusionController
feat: implement IHasFeedback interface in IEssentialsRoomFusionContro…
2025-11-25 13:37:31 -05:00
Neil Dorin
d17394cdd7 feat: add logging to ExecuteSwitch method in GenericSink 2025-11-25 11:06:48 -07:00
Neil Dorin
8467afde38 Update src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-24 17:23:38 -07:00
Neil Dorin
5c016fb4b8 feat: implement IHasFeedback interface in IEssentialsRoomFusionController 2025-11-24 17:14:34 -07:00
Neil Dorin
2fbc32947c Merge pull request #1357 from PepperDash/url-parsing
fix: check for multiple URL patterns for both template & system URLS
2025-11-18 14:14:16 -05:00
Andrew Welker
c06b57a5f9 fix: check for multiple URL patterns for both template & system URLS 2025-11-18 12:30:54 -06:00
Neil Dorin
6d64fffc50 Merge pull request #1356 from PepperDash/mc-subscription-logging
Multiple Fixes
2025-11-14 15:44:58 -05:00
Andrew Welker
0c4ebdaf1d fix: change how subscription state is logged to reduce traffic to console 2025-11-13 09:56:29 -06:00
Andrew Welker
2c49fb9321 fix: parse current Portal URLS for system and template UUIDs correctly 2025-11-12 16:58:23 -06:00
Neil Dorin
c55de61da9 fix: enhance COM port registration logging and update GenericSink class for input switching 2025-11-05 14:43:42 -07:00
Andrew Welker
42444ede0a Merge pull request #1354 from PepperDash/comport-controller-updates
fix: improve logging for COM port registration and configuration
2025-11-04 10:55:44 -05:00
jkdevito
3d50f5f5ac fix: improve logging for COM port registration and configuration 2025-11-04 09:37:14 -06:00
Nick Genovese
11d62aebe1 Merge pull request #1353 from PepperDash/mc-subscription-concurrency
fix: make subscriber functionality thread-safe
2025-11-03 17:26:31 -04:00
Andrew Welker
edc10a9c2a fix: make subscriberIds private & check for add failure 2025-11-03 15:19:17 -06:00
Andrew Welker
9be5823956 Merge branch 'main' into mc-subscription-concurrency 2025-11-03 15:18:45 -06:00
Andrew Welker
35371dde22 fix: make subscriber functionality thread-safe 2025-11-03 15:13:48 -06:00
Jason DeVito
d3ceb4d7e7 Merge pull request #1352 from PepperDash/theme-saving
fix: use correct overload for PostStatusMessage
2025-11-03 15:08:28 -06:00
Andrew Welker
a782b57100 fix: use correct overload for PostStatusMessage 2025-11-03 14:00:51 -06:00
Neil Dorin
1360de599f Merge pull request #1351 from PepperDash/stream-debugging
fix: centralize debug printing into extension methods
2025-11-03 12:19:05 -05:00
Andrew Welker
fd95f5fed1 docs: update XML docs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-03 11:11:00 -06:00
Andrew Welker
9426dff5df fix: copilot suggestions from PR review 2025-11-03 11:02:39 -06:00
Andrew Welker
0d083e63c6 Merge commit '314570d6c3d78c7a92a362f3ec3a4a06bdbebd28' into stream-debugging 2025-11-03 10:56:53 -06:00
Andrew Welker
6ed7c96ec7 fix: centralize debug printing into extension methods
Stream debugging now uses CrestronConsole instead of debug methods, so that the debug statements will be printed regardless of console debug level. This also means that comm debug statements will NOT be in the Crestron Error log or in the files created by the logging system
2025-11-03 10:53:21 -06:00
Andrew Welker
314570d6c3 fix: change number of retained files to 7 instead of 30 for processors 2025-10-31 13:11:50 -05:00
Andrew Welker
ff609dfecd fix: add config option to turn echo off for SSH
In addition, removed CTimer in favor of System.Threading.Timers Timer in the SSH class, and modified the class to be thread-safe.
2025-10-31 09:01:54 -05:00
Andrew Welker
666be5ae59 Merge pull request #1345 from PepperDash/mc-touchpanel-key
mc touchpanel key
2025-10-30 17:11:15 -04:00
Andrew Welker
bfc9b7e7fa fix: logging & ternary changes 2025-10-30 16:07:26 -05:00
Andrew Welker
b02e952765 Merge remote-tracking branch 'origin/com102-comspec' into mc-touchpanel-key 2025-10-30 15:58:36 -05:00
Andrew Welker
72861a5097 Merge remote-tracking branch 'origin/feature/fusion-help-request' into mc-touchpanel-key 2025-10-30 15:58:26 -05:00
Andrew Welker
44ed067f4d chore: update local build version 2025-10-30 15:57:37 -05:00
Andrew Welker
faa2169baf fix: send correct URL to panel 2025-10-30 15:57:28 -05:00
Andrew Welker
fd40b0c6d1 fix: send all status messages with ClientId 2025-10-30 15:57:15 -05:00
Andrew Welker
afcddad1cc fix: remove async on task, as it's unnecessary 2025-10-30 15:56:50 -05:00
Andrew Welker
c4cf8f13e9 fix: register panel in post phase rather than activation cycle 2025-10-30 15:56:28 -05:00
Neil Dorin
c852f87a27 refactor: Comment out logging statements in help request handling 2025-10-30 14:33:58 -06:00
Neil Dorin
071174fa7d feat: Implement help request status tracking in Fusion system 2025-10-30 14:13:02 -06:00
Neil Dorin
da0f28a10c feat: Enhance IEssentialsRoomFusionController with additional properties and logging 2025-10-29 16:47:18 -06:00
Andrew Welker
0538a304ed Merge branch 'main' into mc-touchpanel-key 2025-10-29 15:13:53 -05:00
Andrew Welker
705c5db237 Merge pull request #1347 from PepperDash/json-console
fix: print json response to console using \r\n instead of \n
2025-10-29 16:12:49 -04:00
Neil Dorin
2e95f5337e feat: Add IEssentialsRoomFusionController and related configurations
- Introduced IEssentialsRoomFusionControllerFactory for creating Fusion Room Controller devices.
- Added IEssentialsRoomFusionControllerPropertiesConfig to define configuration properties for the Fusion Room Controller.
- Updated IFusionHelpRequest interface to include methods for cancelling and toggling help requests.
- Refactored RoomOnToDefaultSourceWhenOccupied to use IEssentialsRoomFusionController instead of EssentialsHuddleSpaceFusionSystemControllerBase.
- Modified EssentialsRoomBase to check for IEssentialsRoomFusionController in occupancy status provider.
2025-10-28 16:49:29 -06:00
jkdevito
ba576180a7 refactor: remove unused using directives in ComPortController 2025-10-28 09:05:56 -05:00
jkdevito
92c9db8237 refactor: improve logging messages in ComPort registration and configuration 2025-10-28 09:04:15 -05:00
jkdevito
c4d064965f refactor: enhance ComPortController with additional event documentation and logging improvements 2025-10-28 08:40:29 -05:00
Neil Dorin
f27965ac29 feat: Add help request functionality to Fusion system controller
Introduce `IFusionHelpRequest` interface for managing help requests, including `HelpRequestResponseFeedback` property and `SendHelpRequest` method. Enhance `EssentialsHuddleSpaceFusionSystemControllerBase` with new properties and methods to support help request tracking and management. Improve code organization and documentation throughout the affected files.
2025-10-27 17:35:38 -06:00
jkdevito
3ce282e2db refactor: comment out debug logging for ComPort registration 2025-10-27 17:33:06 -05:00
jkdevito
32a332a6e2 refactor: update TODO comment for Port registration verification 2025-10-27 17:32:40 -05:00
jkdevito
151a90c9be refactor: streamline ComPort registration and configuration logic with enhanced logging 2025-10-27 17:13:43 -05:00
jkdevito
89e893b3b7 fix: improve formatting and logging in ComPortController 2025-10-27 16:46:09 -05:00
jkdevito
d01eb03890 feat: enhance ComPortController with detailed logging on configuration changes 2025-10-27 14:06:20 -05:00
Andrew Welker
16c92afabb fix: print json response to console using \r\n instead of \n 2025-10-27 09:21:51 -05:00
Andrew Welker
dff5d2d32e Merge pull request #1346 from PepperDash/feature/add-infinetEx-comm-method 2025-10-23 18:50:06 -04:00
Neil Dorin
317bde3814 fix: add InfinetEx to eControlMethods enum 2025-10-23 15:22:46 -06:00
Andrew Welker
8bab3dc966 fix: send touchpanelKey message with all room combiner checks 2025-10-23 11:21:17 -05:00
Andrew Welker
514ac850ca fix: send touchpanel key correctly 2025-10-23 10:01:05 -05:00
Andrew Welker
44432f7a41 fix: send touchpanel key to client when client joins direct server 2025-10-23 09:54:03 -05:00
Andrew Welker
99253b30c2 fix: send touchpanel key to client when client joins 2025-10-23 09:49:45 -05:00
Andrew Welker
bf248fe33e Merge pull request #1343 from PepperDash/device-interface-system
device interface system
2025-10-23 10:40:56 -04:00
cdenig
2f44040e4f Merge pull request #1344 from PepperDash/feature/allow-config-tool-v2-structure
Feature/allow config tool v2 structure
2025-10-23 10:15:03 -04:00
Neil Dorin
10399a1be8 Update src/PepperDash.Core/Config/PortalConfigReader.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-22 13:54:08 -06:00
Neil Dorin
5409db193c Update src/PepperDash.Essentials.Core/Config/Essentials/EssentialsConfig.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-22 13:53:23 -06:00
Neil Dorin
f1ce54a524 Merge branch 'main' into feature/allow-config-tool-v2-structure 2025-10-22 13:48:22 -06:00
Andrew Welker
7c72a0d905 fix: send device interface list on client join
In order to avoid updating the MC Edge API to send device interfaces, one of the responses to the clientJoined message will now be a message with the type `/system/deviceInterfaces`. This has a corresponding handler in the core library to put the interfaces in the correct location.
2025-10-21 18:19:09 -05:00
Andrew Welker
5d5e78629e chore: update local build version to 2.18.2-local 2025-10-21 18:17:25 -05:00
Neil Dorin
dab5484d6e Merge pull request #1342 from PepperDash/wsdebug-persistence
Unique Client IDs
2025-10-15 15:16:46 -04:00
Andrew Welker
5c35a3be45 fix: catch exceptions in handlers directly
Previously, any exceptions that were occuring in a hander's action were being swalled due to being off on another thread. Now, those exceptions are caught and printed out.
2025-10-15 14:03:17 -05:00
Andrew Welker
6cb98e12fa fix: use correct collection for program stop 2025-10-15 14:02:06 -05:00
Andrew Welker
608601990b docs: fix Copilot comments 2025-10-15 12:54:14 -05:00
Andrew Welker
3e0f318f7f fix: update log methods to all be consistent 2025-10-15 12:36:42 -05:00
Andrew Welker
98d0cc8fdc docs: add missing XML comments for Mobile Control Project 2025-10-15 12:26:57 -05:00
Andrew Welker
c557c6cdd6 fix: mobileinfo & CWS info call report the correct data 2025-10-15 11:49:06 -05:00
Andrew Welker
8525134ae7 fix: direct server clients now have unique client IDs
Using the generated security token as an ID was presenting problems with duplicate connections using the same ID and trying to figure out where to send the messages. Now, the clients have a unique ID that's an increasing integer that restarts at 1 when the program restarts.
2025-10-15 09:50:12 -05:00
Andrew Welker
1197b15a33 Merge pull request #1340 from PepperDash/display-bridging
Display bridging, Docs, Appdebug
2025-10-10 10:21:35 -04:00
Andrew Welker
ea6a7568fc Merge remote-tracking branch 'origin/feature/add-IKeyed-to-interfaces' into display-bridging 2025-10-09 16:08:17 -05:00
Andrew Welker
3a2a059ce1 fix: appdebug now has option for setting all sink levels 2025-10-09 16:07:25 -05:00
Andrew Welker
f9d9df9d5c docs: XML comments for Devices.Common 2025-10-09 13:18:36 -05:00
Neil Dorin
c284c4275f feat: Enhance UDPServer initialization in Connect method
Updated the `Connect` method in `GenericUdpServer.cs` to include error handling for hostname parsing. The method now attempts to create a `UDPServer` instance with specified parameters and falls back to default initialization if an error occurs. This improves flexibility and robustness in server setup.
2025-10-09 11:31:38 -06:00
Neil Dorin
0418f8a7cc fix: Fix typos and enhance item selection handling
Corrected parameter name in GenericUdpServer constructor.
Added new action for item selection in ISelectableItemsMessenger
with error handling for missing or invalid keys.
Updated SetItems method to improve clarity and ensure proper
clearing and re-adding of item actions.
2025-10-09 09:40:46 -06:00
Andrew Welker
a5d409e93a fix: analog input check uese correct comparison
input selection coming from SIMPL is 1-based, not 0-based. Comparison to input port array length needs to be <= instead of <
2025-10-09 08:36:26 -05:00
Andrew Welker
59944c0e2f refactor: split up classes to separate files 2025-10-09 08:33:22 -05:00
Neil Dorin
419177ccd5 fix: Add item management and update handling in messenger
Introduces a new private field `_itemKeys` to store item keys. Adds the `SetItems` method to manage item actions and update events, ensuring proper registration and cleanup. The `SendFullStatus` method is now invoked from a dedicated event handler `LocalItem_ItemUpdated`, improving the handling of item updates.
2025-10-08 12:24:17 -06:00
Neil Dorin
bd01e2bacc fix: Add KeyName class and update camera messaging
This commit introduces a new `KeyName` class implementing the `IKeyName` interface, enhancing the representation of camera data. The `CameraController_CameraSelected` and `SendFullStatus` methods are updated to utilize `KeyName` instances for selected and listed cameras, improving data encapsulation and consistency in the `IHasCamerasWithControlsStateMessage`. Additionally, new using directives for logging and core functionalities are added.
2025-10-07 17:10:11 -06:00
Neil Dorin
2928c5cf94 feat: Enhance camera capabilities and messaging structure
- Introduced `ICameraCapabilities` interface and `CameraCapabilities` class for defining camera features like pan, tilt, zoom, and focus.
- Modified `IHasCameras` interface to include a list of `IHasCameraControls` objects for improved camera management.
- Refactored `CameraBaseMessenger` to be generic, enhancing flexibility and type safety.
- Updated `SendCameraFullMessageObject` to include detailed camera capabilities in status messages.
- Added `CameraStateMessage` class to encapsulate camera state, including control support and capabilities.
- Updated `IHasCamerasWithControlMessenger` to use `IKeyName` for camera list and selected camera properties, improving type consistency.
- Enhanced `MobileControlSystemController` to manage devices implementing `IHasCameraControls`, creating appropriate messengers for different device types.
2025-10-07 15:37:31 -06:00
Neil Dorin
82b5dc96c1 feat: Deprecate IHasCamerasMessenger; introduce new controls
Mark IHasCamerasMessenger as obsolete and replace it with
IHasCamerasWithControlMessenger, which adds functionality
for devices with camera controls. A new state message class,
IHasCamerasWithControlsStateMessage, has been added to
encapsulate camera state. Update MobileControlSystemController
to use the new messenger implementation.
2025-10-07 12:00:01 -06:00
Neil Dorin
37cea8a11c fix: Refactor camera control interfaces and event arguments
Significantly restructure camera control interfaces and event arguments.
Removed obsolete interfaces like `IHasCameras` and `CameraSelectedEventArgs`,
and introduced generic event argument classes for improved type safety.
Added `IHasCamerasWithControls` for better management of camera controls.
Corrected the `IHasCameraMuteWithUnmuteReqeust` interface name.
Reintroduced the `eCameraControlMode` enum to define camera control modes.
These changes enhance the organization, clarity, and functionality of the camera control system.
2025-10-07 11:52:07 -06:00
Neil Dorin
a3f0901fa0 Merge pull request #1335 from PepperDash/mc-messenger-improvements
feat: unique status requests for messengers
2025-09-30 14:33:07 -06:00
Neil Dorin
f91f435768 fix: Add null check for CurrentScenario in MobileControlSystem
This change introduces a check for `_roomCombiner.CurrentScenario` being `null`. When it is `null`, a `MobileControlMessage` is created with the type `/system/roomKey`, `clientId`, and `roomKey`, which is then sent to the client. This improves the handling of scenarios without a current scenario by ensuring relevant room key information is communicated.
2025-09-30 12:11:25 -06:00
Andrew Welker
5120b2b574 Merge branch 'main' into mc-messenger-improvements 2025-09-29 11:02:39 -05:00
Andrew Welker
7c90027578 feat: set direct server debug level via console command
The `mobilewsdebug` console command can now be used to set the internal websocket logging level for both the API client and the direct server at the same time.
2025-09-26 21:47:06 -05:00
Andrew Welker
bb694b4200 feat: enable subscription logic for messengers
In order to help control traffic over the websocket, a subscription feature has been added:
* A config option, `enableMessengerSubscriptions` has been added
* When true, the MessengerBase class will assume that any message sent using the `PostStatusMessage` that has a valid client ID wants to send any subsequent unsolicited updates to that same client
* The client's ID will be added a list of subscribed client IDs
* Any subsequent messages sent using the `PostStatusMessage` methods that have a null clientId will ONLY be sent to subscribed clients
* When a client disconnects, it will be removed from the list of subscribed clients

This should cut down drastically on the traffic to the UI, especially when combined with requesting partial status updates from a device rather than the entire state.
2025-09-26 21:31:54 -05:00
Andrew Welker
087d0a1149 chore: move classes and interfaces to individual files 2025-09-26 21:21:01 -05:00
Andrew Welker
4747c16b02 build: delete all local build clzs on build 2025-09-26 21:17:28 -05:00
Andrew Welker
aa4d241dde Merge pull request #1337 from PepperDash/Ibasicvolumecontrols-messenger
fix: modify volume messenger to start with IBasicVolumeControls
2025-09-26 10:40:44 -04:00
Andrew Welker
9fc5586531 fix: use IBasicVolumeControls to build DeviceVolumeMessenger 2025-09-25 15:29:35 -05:00
Andrew Welker
d33fd56529 feat: add method to force panel reload
Other refactorings for factory method and log statements
2025-09-25 14:47:11 -05:00
Neil Dorin
8fc4d21f02 fix: Add DeviceInterfaceSupport property to JoinResponse
This commit introduces a new property, `DeviceInterfaceSupport`,
to the `JoinResponse` class in the `PepperDash.Essentials.WebSocketServer`
namespace. This property is a dictionary that maps strings to
`DeviceInterfaceInfo` objects, enhancing support for device interfaces.
A summary comment has also been added for clarity.
2025-09-25 11:50:42 -06:00
Neil Dorin
6d93662b31 Merge pull request #1338 from PepperDash/io-updates 2025-09-25 09:59:36 -06:00
Andrew Welker
11b190e76f docs: put XML comments on correct thing 2025-09-25 10:51:30 -05:00
Andrew Welker
df03a71cbc chore: fix errors in log statements
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-25 09:50:55 -05:00
Andrew Welker
72e67a1c4c fix: implement IHasFeedback for all IO devices and modify logging 2025-09-25 09:47:44 -05:00
Andrew Welker
f8728b6825 docs: update XML comments for EssentialsDeviceFactory 2025-09-25 09:46:55 -05:00
Andrew Welker
d9ef8a2289 docs: add XML comments for IAnalogInput 2025-09-25 09:46:03 -05:00
Andrew Welker
278408a3bc docs: reword XML comments for IHasFeedback Interface 2025-09-25 09:45:42 -05:00
Andrew Welker
fd70377c7f fix: log errors and disconnects for UI Clients 2025-09-25 08:51:11 -05:00
Neil Dorin
06341b14f3 feat: Adds device interface support info to joinroom response in MC websocket server.
Enhance MessengerBase and WebSocketServer functionality

Updated MessengerBase with new methods for action management and message posting, along with improved documentation. Introduced DeviceMessageBase for better message representation.

Enhanced MobileControlWebsocketServer to support device interfaces, adding DeviceInterfaceSupport to JoinResponse and a new DeviceInterfaceInfo class for detailed device information.
2025-09-24 14:49:41 -06:00
Andrew Welker
d7f9c74b2f fix: modify volume messenger to start with IBasicVolumeControls 2025-09-23 13:39:03 -05:00
Andrew Welker
5921b5dbb0 Merge pull request #1336 from PepperDash/hotfix/check-for-cs-lan-on-mctp
Hotfix/check for cs lan on mctp
2025-09-23 13:58:15 -04:00
Neil Dorin
ba0de5128f Update src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-23 11:56:57 -06:00
Andrew Welker
b0a090062f Merge branch 'hotfix/check-for-cs-lan-on-mctp' into mc-messenger-improvements 2025-09-23 11:25:41 -05:00
Andrew Welker
9c0cab8218 fix: use id parameter and fix some formatting 2025-09-23 11:09:44 -05:00
Andrew Welker
c0af637108 fix: use correct property names 2025-09-23 11:07:24 -05:00
Andrew Welker
9c9eaea928 feat: unique status requests for messengers
UI Applications can now request status for specific feature sets instead of full status for a device. This will hopefully cut down on the traffic and messages required to get the data for the UI.
2025-09-23 10:55:16 -05:00
Neil Dorin
9de94bd65f fix: Update v2 config detection criteria
Changed the logic for identifying v2 configuration files. The check now looks for the presence of a "versions" node instead of the absence of "system" or "template" nodes, reflecting an update in the configuration file structure.
2025-09-22 15:05:06 -06:00
Neil Dorin
ff46fb8f29 feat: Add versioning support to EssentialsConfig
Introduce `Versions` property in `EssentialsConfig` to hold version information.
Add `VersionData` class for Essentials and package versions, and `NugetVersion` class for individual package details.
Retain and document `SystemTemplateConfigs` class.
2025-09-22 14:55:58 -06:00
Neil Dorin
d9243def30 feat: Adds ability to read configs generated from v2 config tool that are pre-merged don't have system or template objects
Refactor config handling and improve documentation

- Updated `PortalConfigReader.cs` to use constants for configuration keys, enhancing maintainability and readability. Improved error logging with `Debug.LogError`.
- Modified `ConfigReader.cs` to handle v2 configuration format, streamlining the loading process and avoiding redundant parsing.
- Added XML documentation comments to properties in `EssentialsConfig.cs`, improving code documentation. Initialized `Rooms` property in the constructor.
- Enhanced `SystemTemplateConfigs` class with XML documentation for better clarity on its properties.
2025-09-22 14:22:57 -06:00
Neil Dorin
258699fbcd fix: Enhance AppUrl change logging
Updated logging to include the new AppUrl value when it changes. This provides better context in the logs, making it easier to track the specific URL that was set.
2025-09-18 18:23:12 -06:00
Neil Dorin
738504e9fc fix: Add error handling for network parameter retrieval
Introduced a try-catch block to handle exceptions when fetching the Crestron Ethernet adapter's ID, subnet mask, and IP address. Added logging for cases where the processor lacks a CS LAN. Also included a new using directive for Serilog.Events.
2025-09-18 14:48:21 -06:00
erikdred
cae1bbd6e6 Merge pull request #1332 from PepperDash/feature/add-hide-property-to-room-combine-scenario
feat: Add HideInUi property to room combiner classes
2025-09-17 18:38:21 -04:00
Neil Dorin
dea4407e3e Update src/PepperDash.Essentials.Core/Room/Combining/IEssentialsRoomCombiner.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-17 16:36:33 -06:00
Neil Dorin
ab08a546f7 feat: Add HideInUi property to room combiner classes
- Introduced `HideInUi` property in `EssentialsRoomCombinerPropertiesConfig` to control UI visibility.
- Added `HideInUi` interface property in `IEssentialsRoomCombiner`.
- Implemented `HideInUi` in `RoomCombinationScenario`, along with new `Key` and `Name` properties for improved data representation.
2025-09-17 15:25:23 -06:00
Neil Dorin
ef98d47792 Merge pull request #1331 from PepperDash/dev-list-fix 2025-09-17 08:36:04 -06:00
Andrew Welker
c05976ee60 fix: modify formatting and sorting for devfb response 2025-09-17 09:28:04 -05:00
Andrew Welker
4ca1031bef docs: fix CS1587 errors 2025-09-17 08:52:44 -05:00
Andrew Welker
6d61c4525e fix: use ConsoleCommandResponse for device feedbacks 2025-09-17 08:52:29 -05:00
Andrew Welker
3db274ace5 fix: add line endings for devlist console command 2025-09-17 08:51:45 -05:00
Neil Dorin
f0f708294c Merge pull request #1329 from PepperDash/devlist-fix
fix: print devlist output using ConsoleCommandResponse
2025-09-10 09:58:13 -06:00
Andrew Welker
a00d186c62 fix: print devlist output using ConsoleCommandResponse 2025-09-10 10:45:55 -05:00
Neil Dorin
51da668dfd Merge pull request #1327 from PepperDash/cs-lan-mc-panel
fix: add config property for devices on CS LAN
2025-09-05 16:20:42 -06:00
Andrew Welker
d2b7400039 fix: INvxNetworkPortInformation inherits from IKeyed 2025-09-05 15:55:31 -05:00
Andrew Welker
2424838b7f chore: remove unused using
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-02 12:56:14 -05:00
Andrew Welker
9556edc064 fix: add config property for devices on CS LAN 2025-09-02 12:54:51 -05:00
Sumanth Rayancha
f9088691fd Merge pull request #1322 from PepperDash/release
Release
2025-08-26 10:16:18 -04:00
Andrew Welker
e40b6a8b4c Merge pull request #1320 from PepperDash/feature/extract-html-assets
feat: add html assets extraction from zip files in ControlSystem
2025-08-26 09:58:02 -04:00
Erik Meyer
c3b39a87da fix: enhance zip extraction to prevent directory traversal attacks 2025-08-22 15:15:02 -04:00
erikdred
06dc0e947e fix: check for null when getting directory
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-22 09:12:20 -04:00
aknous
147997f460 Merge pull request #1321 from PepperDash/IBasicVideoMuteWithFeedbackMessenger
Adds IBasicVideoMuteWithFeedbackMessenger
2025-08-21 14:26:10 -04:00
aknous
49abec5eea Update src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-21 13:23:43 -04:00
aknous
6830efe42a fix: fixes CameraBaseMessenger hold timer for PTZ controls, adds storePreset messenger 2025-08-19 18:34:16 -04:00
Neil Dorin
d013068a0c Update src/PepperDash.Essentials/ControlSystem.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-19 14:54:11 -06:00
Neil Dorin
52916d29f4 Update src/PepperDash.Essentials/ControlSystem.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-19 14:53:06 -06:00
Erik Meyer
19e8489166 feat: add html assets extraction from zip files in ControlSystem 2025-08-19 15:48:43 -04:00
Neil Dorin
fe33443b25 fix: Update IP handling in MobileControlTouchpanelController
Updates logic to handle setting the URL sent to the CH5 wrapper app to use the CS LAN IP based on the actual IpInformationChange event on the panel itself.

- Added `._PepperDash.Essentials.4Series.sln` to .gitignore.
- Introduced new using directives for Regex and Crestron libraries.
- Added `csIpAddress` and `csSubnetMask` fields to store device IP info.
- Modified constructor to retrieve and assign current IP and subnet mask.
- Updated `Panel.IpInformationChange` event handler for logging and URL setting.
- Created `GetUrlWithCorrectIp` method to determine the correct URL based on IP.
- Refactored `SetAppUrl` to utilize the new URL method.
- Commented out old IP determination logic in `MobileControlWebsocketServer.cs` as it was moved to the touchpanel controller.
2025-08-19 13:28:45 -06:00
aknous
8cf195b262 feat: adds IBasicVideoMuteWithFeedbackMessenger 2025-08-19 11:37:39 -04:00
Neil Dorin
40406b797d Merge pull request #1314 from PepperDash/streaming-device-properties 2025-08-15 11:52:20 -06:00
Andrew Welker
65bc408ebf fix: add StreamUrl to baseStreamingDeviceProperties 2025-08-15 12:41:21 -05:00
Neil Dorin
9d49fb8357 Merge pull request #1313 from PepperDash/temp-to-dev
Temp to dev
2025-08-15 09:34:41 -06:00
Neil Dorin
fb7797dac7 Merge pull request #1312 from PepperDash/comm-bridge-add 2025-08-15 09:02:23 -06:00
Andrew Welker
574f5f6dc9 chore: remove unused using directives in CommFactory.cs 2025-08-15 09:51:17 -05:00
Andrew Welker
e49c69a12f feat: add CommBridge class and enhance EssentialsBridgeableDevice with new constructors 2025-08-15 09:48:30 -05:00
Sumanth Rayancha
7889cba196 Merge pull request #1307 from PepperDash/feature/assets-folder
feat: add LoadAssets method to manage asset loading and configuration…
2025-08-13 12:08:14 -04:00
Nick Genovese
033aa1f3dd feat: enhance asset extraction and configuration file handling in ControlSystem 2025-08-12 12:17:58 -04:00
Neil Dorin
9b6c2d80ea Merge pull request #1308 from PepperDash/current-sources 2025-08-11 22:53:11 -06:00
Andrew Welker
a0fc731701 chore: apply copilot suggestions
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-11 17:55:02 -05:00
Andrew Welker
f2d0dca7b8 fix: make appdebug case-insensitive
when commands like `appdebug verbose` are used rather than `appdebug 2`, the command would fail because Verbose != verbose. The enum conversion is now case-insensitive.
2025-08-11 17:50:50 -05:00
Andrew Welker
ab4e85d081 fix: use different methods for extensions
The logging extension methods now use the appropriate methods from
the debug class. Previously some messages were not getting handled correctly, and it was causing issues with log statements.
2025-08-11 17:48:46 -05:00
Andrew Welker
47017da527 fix: use correct property names 2025-08-11 17:47:14 -05:00
Andrew Welker
4f0d464ba4 Merge pull request #1306 from PepperDash/fix/remove-unsued-method-in-cs
Fix/remove unsued method in cs
2025-08-11 15:30:04 -05:00
Nick Genovese
0107422507 refactor: remove unused assembly resolution logic from ControlSystem 2025-08-11 16:24:44 -04:00
Nick Genovese
1a366790e7 feat: add LoadAssets method to manage asset loading and configuration file cleanup 2025-08-11 16:23:31 -04:00
Andrew Welker
97448f4f0f Merge branch 'main' into current-sources 2025-08-06 09:01:40 -05:00
Andrew Welker
cf3ece4237 fix: use cr-lf for line endings 2025-08-06 09:00:45 -05:00
Andrew Welker
bb4b2f88b6 Merge pull request #1304 from PepperDash/temp-to-dev
Temp to dev
2025-08-05 16:39:38 -05:00
aknous
808e8042a7 Merge pull request #1305 from PepperDash/default-debug-levels
fix: set default debug levels if not found
2025-08-04 14:47:31 -04:00
Andrew Welker
0bc4388bfd Merge branch 'default-debug-levels' into current-sources 2025-08-04 13:31:26 -05:00
Andrew Welker
dbc132c0da fix: set default debug levels if not found 2025-08-04 13:31:17 -05:00
Andrew Welker
5bb0ab2626 fix: base config properties for use with streaming devices 2025-08-01 21:17:35 -05:00
Andrew Welker
27bf36c58c fix: modify how current sources dictionary gets updated 2025-08-01 09:22:31 -05:00
Andrew Welker
ce886aea63 chore: update local build version 2025-08-01 09:22:31 -05:00
Andrew Welker
ef920bf54c Merge branch 'main' into current-sources 2025-07-31 13:27:43 -05:00
Andrew Welker
88466818ce Merge pull request #1303 from PepperDash/debug-fixes
fix: use correct overload for logging at levels
2025-07-31 13:03:14 -05:00
Andrew Welker
0871a902e1 fix: use correct overload for logging at levels
Some overloads that had the first argument as an Exception were calling the _logger.Write method with a null where the message template should have been, causing messages logged with that overload to be swallowed and not logged.
2025-07-31 12:50:41 -05:00
Andrew Welker
a031424752 fix: add destination & source keys to routelist 2025-07-30 11:20:54 -05:00
Andrew Welker
fd1ba345aa fix: remove StringEnumConverter 2025-07-29 23:01:13 -05:00
Andrew Welker
e03874a7a9 fix: add messenger and event to ICurrentSources 2025-07-29 22:26:07 -05:00
aknous
2efab4f196 Merge pull request #1301 from PepperDash/mc-tp-ip-fix
fix: only adjust IP if processor is a CS processor
2025-07-28 12:57:24 -04:00
Andrew Welker
a41aba1904 Merge pull request #1300 from PepperDash/temp-to-dev
Temp to dev
2025-07-28 11:54:11 -05:00
Andrew Welker
d0ca6721f5 fix: only adjust IP if processor is a CS processor 2025-07-28 11:48:00 -05:00
Andrew Welker
c732eb48f2 Merge pull request #1299 from PepperDash/factory-updates
Multiple Updates
2025-07-25 10:38:15 -05:00
Andrew Welker
efe70208d3 fix: check for null assembly name 2025-07-25 10:32:43 -05:00
Andrew Welker
615f640ebb fix: use continue instead of return
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-25 10:27:50 -05:00
Andrew Welker
ee6f9416a3 chore: remove unused configSnippet 2025-07-25 10:24:32 -05:00
Andrew Welker
4fc6ecbd0b style: switch to auto property for attributes 2025-07-25 09:56:39 -05:00
Andrew Welker
58bcc3315d fix: add changes from code review 2025-07-25 09:51:04 -05:00
Andrew Welker
08cc84a8e8 fix: apply suggestions from code review
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-25 09:28:53 -05:00
Andrew Welker
226014fee0 fix: apply suggestions from code review
- remove commented out debug statements
- null check for description attribute

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-25 09:27:33 -05:00
Andrew Welker
dc7f99e176 fix: mark FeedbackBase default constructor as obsolete
There are situations now where feedbacks in the feedback collection
can be used to update things on UIs. If the feedback doesn't have a key, it can't
be used for this purpose.
2025-07-25 09:18:22 -05:00
Andrew Welker
f0af9f8d19 fix: mark IHasMultipleDisplays and associated enum as obsolete
Fixes #1219
2025-07-25 09:14:45 -05:00
Andrew Welker
31143f56df fix: modify how exceptions are printed to reduce noise
When an exception occurs during the connect method,
only the exception message will be printed at the Error log level.
The entire stack trace will be printed when at the Verbose level.

fixes #1273
2025-07-25 09:13:42 -05:00
Andrew Welker
43989b9588 chore: move interfaces to their own files 2025-07-25 09:12:09 -05:00
Andrew Welker
8db559f197 feat: factory updates & refactoring
This commit introduces significant updates to the device factory system, enhancing the way devices are created and managed within the PepperDash Essentials framework.
The changes include:
- New attributes for device configuration and description.
- Refactoring of the device manager and essentials device classes to support new factory methods.
- modified factory classes for essentials devices, plugin development devices, and processor extension devices.
- The device factory interface has been updated to include a factory method for creating devices.
- Added a wrapper for the device factory to streamline device creation.
- Updated plugin loader to accommodate the new device factory structure.

Fixes #1065
Fixed #1277
2025-07-25 09:05:40 -05:00
Andrew Welker
86f20da116 Merge pull request #1291 from PepperDash/copilot/fix-1290
docs: Add comprehensive XML documentation to all public members
2025-07-25 08:02:37 -05:00
Andrew Welker
0674dbda37 Merge branch 'main' into copilot/fix-1290 2025-07-25 07:48:49 -05:00
Andrew Welker
592607f3c8 Merge pull request #1296 from PepperDash/feature/add-IHasCamerasMessenger 2025-07-24 18:53:05 -05:00
Neil Dorin
ea0a779f8b Merge branch 'feature/add-IHasCamerasMessenger' of https://github.com/PepperDash/Essentials into feature/add-IHasCamerasMessenger 2025-07-24 16:40:06 -06:00
Neil Dorin
86e4d2f7fb feat: Update SendFullStatus to target specific clients
Modified the `SendFullStatus` method to accept a `string clientId` parameter, allowing it to send status messages to specific clients. Updated the action for `"/fullStatus"` to pass the client ID and adjusted the `PostStatusMessage` call accordingly.
2025-07-24 16:39:28 -06:00
Neil Dorin
0069233e13 Update src/PepperDash.Essentials.Devices.Common/Cameras/CameraControl.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-24 16:16:05 -06:00
Neil Dorin
4048efb07e Merge branch 'main' into feature/add-IHasCamerasMessenger 2025-07-24 16:03:41 -06:00
Andrew Welker
b12cdbc75c docs: apply suggestions from copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-23 09:08:10 -05:00
Neil Dorin
b47f1d6b77 Merge pull request #1293 from PepperDash/to-dev 2025-07-23 07:53:44 -06:00
Andrew Welker
1dbac7d1c8 Merge pull request #1292 from PepperDash/portkey-add
feat: add destination and source port key properties for advanced routing
2025-07-22 15:26:44 -05:00
Neil Dorin
799d4c127c Update src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 14:02:01 -06:00
Andrew Welker
a6cd9a0571 feat: add destination and source port key properties for advanced routing 2025-07-22 14:56:28 -05:00
copilot-swe-agent[bot]
80da4ad98f docs: fix duplicate and malformed XML documentation tags
Co-authored-by: andrew-welker <1765622+andrew-welker@users.noreply.github.com>
2025-07-22 17:40:17 +00:00
Andrew Welker
b283ed34b4 docs: remove duplicate
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 12:08:28 -05:00
Andrew Welker
899f13eadb docs: remove duplicate
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 12:08:10 -05:00
Andrew Welker
fc1e29565e docs: remove duplicate
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 12:03:33 -05:00
Andrew Welker
f9a74567d2 docs: remove duplicates
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 12:03:18 -05:00
Andrew Welker
53b1e5d142 docs: remove duplicates
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 12:03:03 -05:00
Andrew Welker
78e9ea8070 docs: duplicate tags
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 12:02:38 -05:00
Andrew Welker
df201558a5 docs: update
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 12:02:24 -05:00
Andrew Welker
130c874684 docs: fix documentation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:37:08 -05:00
Andrew Welker
aee40ffe14 docs: fix duplicate XML tags
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:36:43 -05:00
Andrew Welker
3ffad13abf docs: remove duplicate
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:30:04 -05:00
Andrew Welker
5ee7aaa991 docs: revert to old comment
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:29:25 -05:00
Andrew Welker
4fa8433e73 docs: change wording
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:19:10 -05:00
Andrew Welker
5fe99518a0 docs: update formatting
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:18:50 -05:00
Andrew Welker
5a2a2129e6 docs: remove duplicate
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:13:33 -05:00
Andrew Welker
4fbfda62d6 docs: remove duplicate
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:13:21 -05:00
Andrew Welker
b8ab54cbe0 docs: remove duplicate
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:12:55 -05:00
Andrew Welker
f6f1619bc2 docs: remove duplicate
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:12:38 -05:00
Andrew Welker
41fd4d6adc docs: revert to original documentation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:12:25 -05:00
Andrew Welker
5b73f8fbd2 docs: remove duplicate docs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:12:03 -05:00
Andrew Welker
c70a8edc24 docs: remove duplicate documentation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-22 11:11:33 -05:00
copilot-swe-agent[bot]
7987eb8f9b docs: complete XML documentation for all projects with inheritdoc tags
Co-authored-by: andrew-welker <1765622+andrew-welker@users.noreply.github.com>
2025-07-22 15:53:01 +00:00
copilot-swe-agent[bot]
260677a37f docs: add XML documentation to PepperDash.Core project
Co-authored-by: andrew-welker <1765622+andrew-welker@users.noreply.github.com>
2025-07-22 15:48:23 +00:00
copilot-swe-agent[bot]
eeb0e84dc7 docs: enable XML documentation generation and add initial documentation
Co-authored-by: andrew-welker <1765622+andrew-welker@users.noreply.github.com>
2025-07-22 15:44:52 +00:00
copilot-swe-agent[bot]
d282487da6 Initial plan 2025-07-22 15:35:41 +00:00
Andrew Welker
da30424657 Merge pull request #1289 from PepperDash/meter-feedback-interface
meter feedback interface
2025-07-21 15:20:29 -05:00
Andrew Welker
311452beac fix: use correct namespaces
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-21 13:30:11 -05:00
Andrew Welker
789113008e docs: update comments
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-21 13:29:11 -05:00
Andrew Welker
660836bd5a docs: remove spaces
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-21 13:28:59 -05:00
Andrew Welker
97b2ffed9c docs: fix comment
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-21 13:28:37 -05:00
Andrew Welker
2bbefa062d docs: fix comments
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-21 13:28:10 -05:00
Andrew Welker
3421b2f28c Merge branch 'main' into meter-feedback-interface 2025-07-17 12:34:16 -05:00
Andrew Welker
82889e9794 Merge pull request #1288 from PepperDash/mc-touchpanel-cs
Backwards Compatibility issues
2025-07-17 12:33:01 -05:00
Andrew Welker
1dcd4e328c fix: Destination support for USB 2025-07-17 12:32:26 -05:00
Andrew Welker
e76369726d docs: XML comments for DestinationListItem 2025-07-17 12:25:52 -05:00
Andrew Welker
2bf0f2092b fix: use new interface in direct server 2025-07-17 12:16:32 -05:00
Neil Dorin
f8455d4110 feat: Refactor IHasCamerasMessenger constructor parameters
Updated the constructor of `IHasCamerasMessenger` to reorder parameters, placing `IHasCameras cameraController` last. Added logic in `MobileControlSystemController.cs` to instantiate and add `IHasCamerasMessenger` for devices implementing the `IHasCameras` interface.
2025-07-17 11:14:32 -06:00
Andrew Welker
c1eccfd790 fix: refactor interfaces for backwards compatibility 2025-07-17 12:13:08 -05:00
aknous
f1a89161bc Merge pull request #1287 from PepperDash/mc-touchpanel-cs
fix: use Control Subnet IP if MC TP devices are on the CS Lan
2025-07-17 11:17:03 -04:00
Andrew Welker
e59c50d0aa refactor: use tryParse for IP Address parsing
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-17 10:15:19 -05:00
Andrew Welker
9d313d8c7c fix: use Control Subnet IP if MC TP devices are on the CS Lan 2025-07-17 09:54:08 -05:00
Andrew Welker
9813673b66 feat: ICurrentSources interface to allow for tracking breakaway routing 2025-07-17 09:15:25 -05:00
Neil Dorin
f006ed0076 feat: Add camera control interfaces and messenger classes
This commit introduces new interfaces in `CameraControl.cs` for various camera functionalities, including muting, panning, tilting, zooming, and auto modes. The `IHasCameras` interface is expanded to manage camera lists and selections, with the addition of `CameraSelectedEventArgs` for event handling.

In `CameraBaseMessenger.cs`, a new `IHasCamerasMessenger` class is created to facilitate communication for devices implementing the `IHasCameras` interface, along with the `IHasCamerasStateMessage` class to represent the state of camera devices. These changes enhance the overall camera control capabilities and improve interaction management within the application.
2025-07-16 16:54:57 -06:00
Andrew Welker
ddbcc13c50 fix: add property for sync device association 2025-07-16 10:41:46 -05:00
Andrew Welker
2a70fc678e fix: add IStateFeedback interface 2025-07-11 13:13:52 -05:00
Andrew Welker
056614cba1 fix: add IMeterFeedback interface 2025-07-09 14:32:01 -05:00
Neil Dorin
5ff587a8c9 Merge pull request #1285 from PepperDash/feature/add-isMic-support
feat: Update .gitignore and enhance routing-related classes
2025-07-08 10:55:05 -06:00
Neil Dorin
26c1baa1f8 Merge pull request #1284 from PepperDash/network-port 2025-07-07 09:19:42 -06:00
Andrew Welker
2b15c2a56f docs: remove extra space
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-07 10:17:37 -05:00
Andrew Welker
a076d531bc chore: remove BOM
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-07 10:17:08 -05:00
Andrew Welker
5e880f0111 chore: add missing brace 2025-07-07 10:06:23 -05:00
Andrew Welker
8f1fb86d37 fix: add NVX network port info interface 2025-07-07 09:49:01 -05:00
Neil Dorin
2fa297a204 feat: Update .gitignore and enhance routing-related classes
- Updated `.gitignore` to include additional files and directories.
- Added summary comments and new properties in `LevelControlListItem.cs` for better clarity and functionality.
- Enhanced documentation in `SourceListItem.cs` and introduced new properties, including `Destinations` and a `ToString` method.
- Introduced `SourceRouteListItem` class with routing properties and expanded `eSourceListItemDestinationTypes` enum.
- Added `IRoutingSinkWithInputPort` interface in `IRoutingSink.cs` to support input port functionality.
2025-06-26 10:10:09 -06:00
696 changed files with 66397 additions and 53065 deletions

View File

@@ -1,247 +0,0 @@
name: Essentials v3 Development Build
on:
push:
branches:
- feature-3.0.0/*
- hotfix-3.0.0/*
- release-3.0.0/*
- development-3.0.0
env:
SOLUTION_PATH: .
SOLUTION_FILE: PepperDash.Essentials
VERSION: 0.0.0-buildtype-buildnumber
BUILD_TYPE: Debug
RELEASE_BRANCH: main
jobs:
Build_Project_4-Series:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Detect environment (Act vs GitHub)
- name: Detect environment
id: detect_env
run: |
if [ -n "$ACT" ]; then
echo "is_local=true" >> $GITHUB_OUTPUT
else
echo "is_local=false" >> $GITHUB_OUTPUT
fi
- name: Install prerequisites
run: |
if [ "${{ steps.detect_env.outputs.is_local }}" == "true" ]; then
# For Act - no sudo needed
apt-get update
apt-get install -y curl wget libicu-dev git unzip
else
# For GitHub runners - sudo required
sudo apt-get update
sudo apt-get install -y curl wget libicu-dev git unzip
fi
- name: Set Version Number
id: setVersion
shell: bash
run: |
latestVersion="3.0.0"
newVersion=$latestVersion
phase=""
newVersionString=""
if [[ $GITHUB_REF =~ ^refs/pull/.* ]]; then
phase="beta"
newVersionString="${newVersion}-${phase}-${GITHUB_RUN_NUMBER}"
elif [[ $GITHUB_REF =~ ^refs/heads/hotfix-3.0.0/.* ]]; then
phase="hotfix"
newVersionString="${newVersion}-${phase}-${GITHUB_RUN_NUMBER}"
elif [[ $GITHUB_REF =~ ^refs/heads/feature-3.0.0/.* ]]; then
phase="alpha"
newVersionString="${newVersion}-${phase}-${GITHUB_RUN_NUMBER}"
elif [[ $GITHUB_REF == "refs/heads/development-3.0.0" ]]; then
phase="beta"
newVersionString="${newVersion}-${phase}-${GITHUB_RUN_NUMBER}"
elif [[ $GITHUB_REF =~ ^refs/heads/release-3.0.0/.* ]]; then
version=$(echo $GITHUB_REF | awk -F '/' '{print $NF}' | sed 's/v//')
phase="rc"
newVersionString="${version}-${phase}-${GITHUB_RUN_NUMBER}"
else
# For local builds or unrecognized branches
newVersionString="${newVersion}-local"
fi
echo "version=$newVersionString" >> $GITHUB_OUTPUT
# Create Build Properties file
- name: Create Build Properties
run: |
cat > Directory.Build.props << EOF
<Project>
<PropertyGroup>
<Version>${{ steps.setVersion.outputs.version }}</Version>
<AssemblyVersion>${{ steps.setVersion.outputs.version }}</AssemblyVersion>
<FileVersion>${{ steps.setVersion.outputs.version }}</FileVersion>
<InformationalVersion>${{ steps.setVersion.outputs.version }}</InformationalVersion>
<PackageVersion>${{ steps.setVersion.outputs.version }}</PackageVersion>
<NuGetVersion>${{ steps.setVersion.outputs.version }}</NuGetVersion>
</PropertyGroup>
</Project>
EOF
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.0.x'
- name: Restore NuGet Packages
run: dotnet restore ${SOLUTION_FILE}.sln
- name: Build Solution
run: dotnet build ${SOLUTION_FILE}.sln --configuration ${BUILD_TYPE} --no-restore
# Copy the CPZ file to the output directory with version in the filename
- name: Copy and Rename CPZ Files
run: |
mkdir -p ./output/cpz
# Find the main CPZ file in the build output
if [ -f "./src/PepperDash.Essentials/bin/${BUILD_TYPE}/net8/PepperDashEssentials.cpz" ]; then
cp "./src/PepperDash.Essentials/bin/${BUILD_TYPE}/net8/PepperDashEssentials.cpz" "./output/cpz/PepperDashEssentials.${{ steps.setVersion.outputs.version }}.cpz"
echo "Main CPZ file copied and renamed successfully."
else
echo "Warning: Main CPZ file not found at expected location."
find ./src -name "*.cpz" | xargs -I {} cp {} ./output/cpz/
fi
- name: Pack Solution
run: dotnet pack ${SOLUTION_FILE}.sln --configuration ${BUILD_TYPE} --output ./output/nuget --no-build
# List build artifacts (runs in both environments)
- name: List Build Artifacts
run: |
echo "=== Build Artifacts ==="
echo "NuGet Packages:"
find ./output/nuget -type f | sort
echo ""
echo "CPZ/CPLZ Files:"
find ./output -name "*.cpz" -o -name "*.cplz" | sort
echo "======================="
# Enhanced package inspection for local runs
- name: Inspect NuGet Packages
if: steps.detect_env.outputs.is_local == 'true'
run: |
echo "=== NuGet Package Details ==="
for pkg in $(find ./output/nuget -name "*.nupkg"); do
echo "Package: $(basename "$pkg")"
echo "Size: $(du -h "$pkg" | cut -f1)"
# Extract and show package contents
echo "Contents:"
unzip -l "$pkg" | tail -n +4 | head -n -2
echo "--------------------------"
# Try to extract and show the nuspec file (contains metadata)
echo "Metadata:"
unzip -p "$pkg" "*.nuspec" 2>/dev/null | grep -E "(<id>|<version>|<description>|<authors>|<dependencies>)" || echo "Metadata extraction failed"
echo "--------------------------"
done
echo "==========================="
# Tag creation - GitHub version
- name: Create tag for non-rc builds (GitHub)
if: ${{ !contains(steps.setVersion.outputs.version, 'rc') && steps.detect_env.outputs.is_local == 'false' }}
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
git tag ${{ steps.setVersion.outputs.version }}
git push --tags origin
# Tag creation - Act mock version
- name: Create tag for non-rc builds (Act Mock)
if: ${{ !contains(steps.setVersion.outputs.version, 'rc') && steps.detect_env.outputs.is_local == 'true' }}
run: |
echo "Would create git tag: ${{ steps.setVersion.outputs.version }}"
echo "Would push tag to: origin"
# Release creation - GitHub version
- name: Create Release (GitHub)
if: steps.detect_env.outputs.is_local == 'false'
id: create_release
uses: ncipollo/release-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
artifacts: 'output/cpz/*,output/**/*.cplz'
generateReleaseNotes: true
prerelease: ${{contains('debug', env.BUILD_TYPE)}}
tag: ${{ steps.setVersion.outputs.version }}
# Release creation - Act mock version with enhanced output
- name: Create Release (Act Mock)
if: steps.detect_env.outputs.is_local == 'true'
run: |
echo "=== Mock Release Creation ==="
echo "Would create release with:"
echo "- Tag: ${{ steps.setVersion.outputs.version }}"
echo "- Prerelease: ${{contains('debug', env.BUILD_TYPE)}}"
echo "- Artifacts matching pattern: output/cpz/*,output/**/*.cplz"
echo ""
echo "Matching artifacts:"
find ./output/cpz -type f
find ./output -name "*.cplz"
# Detailed info about release artifacts
echo ""
echo "Artifact Details:"
for artifact in $(find ./output/cpz -type f; find ./output -name "*.cplz"); do
echo "File: $(basename "$artifact")"
echo "Size: $(du -h "$artifact" | cut -f1)"
echo "Created: $(stat -c %y "$artifact")"
echo "MD5: $(md5sum "$artifact" | cut -d' ' -f1)"
echo "--------------------------"
done
echo "============================"
# NuGet setup - GitHub version
- name: Setup NuGet (GitHub)
if: steps.detect_env.outputs.is_local == 'false'
run: |
dotnet nuget add source https://nuget.pkg.github.com/pepperdash/index.json -n github -u pepperdash -p ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text
# NuGet setup - Act mock version
- name: Setup NuGet (Act Mock)
if: steps.detect_env.outputs.is_local == 'true'
run: |
echo "=== Mock NuGet Setup ==="
echo "Would add GitHub NuGet source: https://nuget.pkg.github.com/pepperdash/index.json"
echo "======================="
# Publish to NuGet - GitHub version
- name: Publish to Nuget (GitHub)
if: steps.detect_env.outputs.is_local == 'false'
run: dotnet nuget push ./output/nuget/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
# Publish to NuGet - Act mock version
- name: Publish to Nuget (Act Mock)
if: steps.detect_env.outputs.is_local == 'true'
run: |
echo "=== Mock Publish to NuGet ==="
echo "Would publish the following packages to https://api.nuget.org/v3/index.json:"
find ./output/nuget -name "*.nupkg" | sort
echo "============================="
# Publish to GitHub NuGet - GitHub version
- name: Publish to Github Nuget (GitHub)
if: steps.detect_env.outputs.is_local == 'false'
run: dotnet nuget push ./output/nuget/*.nupkg --source github --api-key ${{ secrets.GITHUB_TOKEN }}
# Publish to GitHub NuGet - Act mock version
- name: Publish to Github Nuget (Act Mock)
if: steps.detect_env.outputs.is_local == 'true'
run: |
echo "=== Mock Publish to GitHub NuGet ==="
echo "Would publish the following packages to the GitHub NuGet registry:"
find ./output/nuget -name "*.nupkg" | sort
echo "=================================="

5
.gitignore vendored
View File

@@ -393,4 +393,7 @@ essentials-framework/Essentials Interfaces/PepperDash_Essentials_Interfaces/Pepp
/._PepperDash.Essentials.sln
.vscode/settings.json
_site/
api/
api/
*.DS_Store
/._PepperDash.Essentials.4Series.sln
dotnet

9
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,9 @@
{
"recommendations": [
"ms-dotnettools.vscode-dotnet-runtime",
"ms-dotnettools.csharp",
"ms-dotnettools.csdevkit",
"vivaxy.vscode-conventional-commits",
"mhutchie.git-graph"
]
}

View File

@@ -0,0 +1,282 @@
# Crestron Library Usage Analysis - PepperDash Essentials
This document provides a comprehensive analysis of Crestron classes and interfaces used throughout the PepperDash Essentials framework, organized by namespace and library component.
## Executive Summary
The PepperDash Essentials framework extensively leverages Crestron SDK components across 100+ files, providing abstractions for:
- Control system hardware (processors, touchpanels, IO devices)
- Communication interfaces (Serial, TCP/IP, SSH, CEC, IR)
- Device management and routing
- User interface components and smart objects
- System monitoring and diagnostics
## 1. Core Crestron Libraries
### 1.1 Crestron.SimplSharp
**Primary Usage**: Foundational framework components, collections, and basic types.
**Key Files**:
- Multiple files across all projects use `Crestron.SimplSharp` namespaces
- Provides basic C# runtime support for Crestron processors
### 1.2 Crestron.SimplSharpPro
**Primary Usage**: Main hardware abstraction layer for Crestron devices.
**Key Classes Used**:
#### CrestronControlSystem
- **File**: `/src/PepperDash.Essentials/ControlSystem.cs`
- **Usage**: Base class for the main control system implementation
- **Implementation**: `public class ControlSystem : CrestronControlSystem, ILoadConfig`
#### Device (Base Class)
- **Files**: 50+ files inherit from or use this class
- **Key Implementations**:
- `/src/PepperDash.Core/Device.cs` - Core device abstraction
- `/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs` - Extended device base
- `/src/PepperDash.Essentials.Core/Room/Room.cs` - Room device implementation
- `/src/PepperDash.Essentials.Core/Devices/CrestronProcessor.cs` - Processor device wrapper
#### BasicTriList
- **Files**: 30+ files use this class extensively
- **Primary Usage**: Touchpanel communication and SIMPL bridging
- **Key Files**:
- `/src/PepperDash.Essentials.Core/Touchpanels/TriListExtensions.cs` - Extension methods for signal handling
- `/src/PepperDash.Essentials.Core/Devices/EssentialsBridgeableDevice.cs` - Bridge interface
- `/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs` - UI dialog implementation
#### BasicTriListWithSmartObject
- **Files**: Multiple touchpanel and UI files
- **Usage**: Enhanced touchpanel support with smart object integration
- **Key Files**:
- `/src/PepperDash.Essentials.Core/Touchpanels/Interfaces.cs` - Interface definitions
- `/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferenceList/SubpageReferenceList.cs`
## 2. Communication Hardware
### 2.1 Serial Communication (ComPort)
**Primary Class**: `ComPort`
**Key Files**:
- `/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs`
- `/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs`
**Usage Pattern**:
```csharp
public class ComPortController : Device, IBasicCommunicationWithStreamDebugging
public static ComPort GetComPort(EssentialsControlPropertiesConfig config)
```
**Interface Support**: `IComPorts` - Used for devices that provide multiple COM ports
### 2.2 IR Communication (IROutputPort)
**Primary Class**: `IROutputPort`
**Key Files**:
- `/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs`
- `/src/PepperDash.Essentials.Core/Devices/GenericIRController.cs`
- `/src/PepperDash.Essentials.Core/Comm and IR/IRPortHelper.cs`
**Usage Pattern**:
```csharp
public class IrOutputPortController : Device
IROutputPort IrPort;
public IrOutputPortController(string key, IROutputPort port, string irDriverFilepath)
```
### 2.3 CEC Communication (ICec)
**Primary Interface**: `ICec`
**Key Files**:
- `/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs`
- `/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs`
**Usage Pattern**:
```csharp
public class CecPortController : Device, IBasicCommunicationWithStreamDebugging
public static ICec GetCecPort(ControlPropertiesConfig config)
```
## 3. Input/Output Hardware
### 3.1 Digital Input
**Primary Interface**: `IDigitalInput`
**Key Files**:
- `/src/PepperDash.Essentials.Core/CrestronIO/GenericDigitalInputDevice.cs`
- `/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyController.cs`
**Usage Pattern**:
```csharp
public List<IDigitalInput> Inputs { get; private set; }
void AddInput(IDigitalInput input)
```
### 3.2 Versiport Support
**Key Files**:
- `/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs`
- `/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs`
- `/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs`
**Usage**: Provides flexible I/O port configuration for various signal types
## 4. Touchpanel Hardware
### 4.1 MPC3 Touchpanel
**Primary Class**: `MPC3Basic`
**Key File**: `/src/PepperDash.Essentials.Core/Touchpanels/Mpc3Touchpanel.cs`
**Usage Pattern**:
```csharp
public class Mpc3TouchpanelController : Device
readonly MPC3Basic _touchpanel;
_touchpanel = processor.ControllerTouchScreenSlotDevice as MPC3Basic;
```
### 4.2 TSW Series Support
**Evidence**: References found in messenger files and mobile control components
**Usage**: Integrated through mobile control messaging system for TSW touchpanel features
## 5. Timer and Threading
### 5.1 CTimer
**Primary Class**: `CTimer`
**Key File**: `/src/PepperDash.Core/PasswordManagement/PasswordManager.cs`
**Usage Pattern**:
```csharp
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Started"));
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Reset"));
```
## 6. Networking and Communication
### 6.1 Ethernet Communication
**Libraries Used**:
- `Crestron.SimplSharpPro.EthernetCommunication`
- `Crestron.SimplSharp.Net.Utilities.EthernetHelper`
**Key Files**:
- `/src/PepperDash.Core/Comm/GenericTcpIpClient.cs`
- `/src/PepperDash.Core/Comm/GenericTcpIpServer.cs`
- `/src/PepperDash.Core/Comm/GenericSecureTcpIpClient.cs`
- `/src/PepperDash.Core/Comm/GenericSshClient.cs`
- `/src/PepperDash.Core/Comm/GenericUdpServer.cs`
**Usage Pattern**:
```csharp
public class GenericTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
public class GenericSecureTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
```
## 7. Device Management Libraries
### 7.1 DeviceSupport
**Library**: `Crestron.SimplSharpPro.DeviceSupport`
**Usage**: Core device support infrastructure used throughout the framework
### 7.2 DM (DigitalMedia)
**Library**: `Crestron.SimplSharpPro.DM`
**Usage**: Digital media routing and switching support
**Evidence**: Found in routing configuration and DM output card references
## 8. User Interface Libraries
### 8.1 UI Components
**Library**: `Crestron.SimplSharpPro.UI`
**Usage**: User interface elements and touchpanel controls
### 8.2 Smart Objects
**Key Files**:
- `/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDynamicList.cs`
- `/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferenceList/SubpageReferenceList.cs`
**Usage**: Advanced UI components with dynamic content
## 9. System Monitoring and Diagnostics
### 9.1 Diagnostics
**Library**: `Crestron.SimplSharpPro.Diagnostics`
**Usage**: System health monitoring and performance tracking
### 9.2 System Information
**Key Files**:
- `/src/PepperDash.Essentials.Core/Monitoring/SystemMonitorController.cs`
**Usage**: Provides system status, Ethernet information, and program details
## 10. Integration Patterns
### 10.1 SIMPL Bridging
**Pattern**: Extensive use of `BasicTriList` for SIMPL integration
**Files**: Bridge classes throughout the framework implement `LinkToApi` methods:
```csharp
public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge);
```
### 10.2 Device Factory Pattern
**Implementation**: Factory classes create hardware-specific implementations
**Example**: `CommFactory.cs` provides communication device creation
### 10.3 Extension Methods
**Pattern**: Extensive use of extension methods for Crestron classes
**Example**: `TriListExtensions.cs` adds 30+ extension methods to `BasicTriList`
## 11. Signal Processing
### 11.1 Signal Types
**Bool Signals**: Digital control and feedback
**UShort Signals**: Analog values and numeric data
**String Signals**: Text and configuration data
**Implementation**: Comprehensive signal handling in `TriListExtensions.cs`
## 12. Error Handling and Logging
**Pattern**: Consistent use of Crestron's Debug logging throughout
**Examples**:
```csharp
Debug.LogMessage(LogEventLevel.Information, "Device {0} is not a valid device", dc.PortDeviceKey);
Debug.LogMessage(LogEventLevel.Debug, "Error Waking Panel. Maybe testing with Xpanel?");
```
## 13. Threading and Synchronization
**Components**:
- CTimer for time-based operations
- Thread-safe collections and patterns
- Event-driven programming models
## Conclusion
The PepperDash Essentials framework demonstrates sophisticated integration with the Crestron ecosystem, leveraging:
- **Core Infrastructure**: CrestronControlSystem, Device base classes
- **Communication**: COM, IR, CEC, TCP/IP, SSH protocols
- **Hardware Abstraction**: Touchpanels, I/O devices, processors
- **User Interface**: Smart objects, signal processing, SIMPL bridging
- **System Services**: Monitoring, diagnostics, device management
This analysis shows that Essentials serves as a comprehensive middleware layer, abstracting Crestron hardware complexities while providing modern software development patterns and practices.
---
*Generated: [Current Date]*
*Framework Version: PepperDash Essentials (Based on codebase analysis)*

View File

@@ -1,7 +0,0 @@
{
"runtimeOptions": {
"configProperties": {
"System.Globalization.Invariant": false
}
}
}

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>3.0.0-local</Version>
<Version>2.19.4-local</Version>
<InformationalVersion>$(Version)</InformationalVersion>
<Authors>PepperDash Technology</Authors>
<Company>PepperDash Technology</Company>

View File

@@ -23,23 +23,32 @@
<FileName>$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz</FileName>
</PropertyGroup>
<Target Name="DeleteCLZ" BeforeTargets="PreBuildEvent" Condition="$(ProjectType) == 'Library' And $(TargetDir) != '' And Exists($(FileName))">
<Delete Files="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).clz">
<Target Name="DeleteCLZ" BeforeTargets="CoreBuild" Condition="$(ProjectType) == 'Library' And $(TargetDir) != ''">
<ItemGroup>
<OldCLZFiles Include="$(TargetDir)$(TargetName).*.$(TargetFramework).clz" />
</ItemGroup>
<Delete Files="@(OldCLZFiles)" Condition="@(OldCLZFiles) != ''">
<Output TaskParameter="DeletedFiles" ItemName="DeletedList"/>
</Delete>
<Message Text="Deleted files: '@(DeletedList)'" />
<Message Text="Deleted old CLZ files: '@(DeletedList)'" Condition="@(DeletedList) != ''" />
</Target>
<Target Name="DeleteCPZ" BeforeTargets="PreBuildEvent" Condition="$(ProjectType) == 'Program' And $(TargetDir) != '' And Exists($(FileName))">
<Delete Files="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz">
<Target Name="DeleteCPZ" BeforeTargets="CoreBuild" Condition="$(ProjectType) == 'Program' And $(TargetDir) != ''">
<ItemGroup>
<OldCPZFiles Include="$(TargetDir)$(TargetName).*.$(TargetFramework).cpz" />
</ItemGroup>
<Delete Files="@(OldCPZFiles)" Condition="@(OldCPZFiles) != ''">
<Output TaskParameter="DeletedFiles" ItemName="DeletedList"/>
</Delete>
<Message Text="Deleted files: '@(DeletedList)'" />
<Message Text="Deleted old CPZ files: '@(DeletedList)'" Condition="@(DeletedList) != ''" />
</Target>
<Target Name="DeleteCPLZ" BeforeTargets="PreBuildEvent" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != '' And Exists($(FileName))">
<Delete Files="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz">
<Target Name="DeleteCPLZ" BeforeTargets="CoreBuild" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != ''">
<ItemGroup>
<OldCPLZFiles Include="$(TargetDir)$(TargetName).*.$(TargetFramework).cplz" />
</ItemGroup>
<Delete Files="@(OldCPLZFiles)" Condition="@(OldCPLZFiles) != ''">
<Output TaskParameter="DeletedFiles" ItemName="DeletedList"/>
</Delete>
<Message Text="Deleted files: '@(DeletedList)'" />
<Message Text="Deleted old CPLZ files: '@(DeletedList)'" Condition="@(DeletedList) != ''" />
</Target>
<Target Name="CreateCPLZ" AfterTargets="Build" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != ''" DependsOnTargets="DeleteCPLZ">

View File

@@ -0,0 +1,43 @@
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace PepperDash.Core
{
/// <summary>
/// Helper class for formatting communication text and byte data for debugging purposes.
/// </summary>
public class ComTextHelper
{
/// <summary>
/// Gets escaped text for a byte array
/// </summary>
/// <param name="bytes"></param>
/// <returns>string with all bytes escaped</returns>
public static string GetEscapedText(byte[] bytes)
{
return string.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray());
}
/// <summary>
/// Gets escaped text for a string
/// </summary>
/// <param name="text"></param>
/// <returns>string with all bytes escaped</returns>
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());
}
/// <summary>
/// Gets debug text for a string
/// </summary>
/// <param name="text"></param>
/// <returns>string with all non-printable characters escaped</returns>
public static string GetDebugText(string text)
{
return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value));
}
}
}

View File

@@ -8,8 +8,8 @@ using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash.Core;
namespace PepperDash.Core
{
/// <summary>
/// Defines the string event handler for line events on the gather
/// </summary>
@@ -30,7 +30,7 @@ namespace PepperDash.Core;
/// <summary>
/// The communication port that this gathers on
/// </summary>
public ICommunicationReceiver Port { get; private set; }
public ICommunicationReceiver Port { get; private set; }
/// <summary>
/// Default false. If true, the delimiter will be included in the line output
@@ -67,27 +67,26 @@ namespace PepperDash.Core;
/// </summary>
/// <param name="port"></param>
/// <param name="delimiter"></param>
public CommunicationGather(ICommunicationReceiver port, string delimiter)
:this(port, new string[] { delimiter} )
public CommunicationGather(ICommunicationReceiver port, string delimiter)
:this(port, new string[] { delimiter} )
{
}
/// <summary>
/// Constructor for using an array of string delimiters
/// </summary>
/// <param name="port"></param>
/// <param name="delimiters"></param>
public CommunicationGather(ICommunicationReceiver port, string[] delimiters)
{
Port = port;
StringDelimiters = delimiters;
port.TextReceived += Port_TextReceivedStringDelimiter;
}
/// <summary>
/// Constructor for using an array of string delimiters
/// </summary>
/// <param name="port"></param>
/// <param name="delimiters"></param>
public CommunicationGather(ICommunicationReceiver port, string[] delimiters)
{
Port = port;
StringDelimiters = delimiters;
port.TextReceived += Port_TextReceivedStringDelimiter;
}
/// <summary>
/// Disconnects this gather from the Port's TextReceived event. This will not fire LineReceived
/// after the this call.
/// </summary>
/// <summary>
/// Stop method
/// </summary>
public void Stop()
{
Port.TextReceived -= Port_TextReceived;
@@ -136,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)
{
var lines = Regex.Split(str, delimiter);
if (lines.Length == 1)
continue;
for (int i = 0; i < lines.Length - 1; i++)
// Iterate the delimiters and fire an event for any matching delimiter
foreach (var delimiter in StringDelimiters)
{
string strToSend = null;
if (IncludeDelimiter)
strToSend = lines[i] + delimiter;
else
strToSend = lines[i];
handler(this, new GenericCommMethodReceiveTextArgs(strToSend, delimiter));
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]);
}
ReceiveBuffer = new StringBuilder(lines[lines.Length - 1]);
}
}
}
@@ -175,4 +174,5 @@ namespace PepperDash.Core;
{
Stop();
}
}
}
}

View File

@@ -1,176 +1,138 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash.Core;
/// <summary>
/// Controls the ability to disable/enable debugging of TX/RX data sent to/from a device with a built in timer to disable
/// </summary>
public class CommunicationStreamDebugging
namespace PepperDash.Core
{
/// <summary>
/// Device Key that this instance configures
/// Controls the ability to disable/enable debugging of TX/RX data sent to/from a device with a built in timer to disable
/// </summary>
public string ParentDeviceKey { get; private set; }
/// <summary>
/// Timer to disable automatically if not manually disabled
/// </summary>
private CTimer DebugExpiryPeriod;
/// <summary>
/// The current debug setting
/// </summary>
public eStreamDebuggingSetting DebugSetting { get; private set; }
private uint _DebugTimeoutInMs;
private const uint _DefaultDebugTimeoutMin = 30;
/// <summary>
/// Timeout in Minutes
/// </summary>
public uint DebugTimeoutMinutes
public class CommunicationStreamDebugging
{
get
/// <summary>
/// Device Key that this instance configures
/// </summary>
public string ParentDeviceKey { get; private set; }
/// <summary>
/// Timer to disable automatically if not manually disabled
/// </summary>
private CTimer DebugExpiryPeriod;
/// <summary>
/// Gets or sets the DebugSetting
/// </summary>
public eStreamDebuggingSetting DebugSetting { get; private set; }
private uint _DebugTimeoutInMs;
private const uint _DefaultDebugTimeoutMin = 30;
/// <summary>
/// Timeout in Minutes
/// </summary>
public uint DebugTimeoutMinutes
{
return _DebugTimeoutInMs/60000;
}
}
/// <summary>
/// Indicates that receive stream debugging is enabled
/// </summary>
public bool RxStreamDebuggingIsEnabled{ get; private set; }
/// <summary>
/// Indicates that transmit stream debugging is enabled
/// </summary>
public bool TxStreamDebuggingIsEnabled { get; private set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="parentDeviceKey"></param>
public CommunicationStreamDebugging(string parentDeviceKey)
{
ParentDeviceKey = parentDeviceKey;
}
/// <summary>
/// Sets the debugging setting and if not setting to off, assumes the default of 30 mintues
/// </summary>
/// <param name="setting"></param>
public void SetDebuggingWithDefaultTimeout(eStreamDebuggingSetting setting)
{
if (setting == eStreamDebuggingSetting.Off)
{
DisableDebugging();
return;
get
{
return _DebugTimeoutInMs / 60000;
}
}
SetDebuggingWithSpecificTimeout(setting, _DefaultDebugTimeoutMin);
}
/// <summary>
/// Gets or sets the RxStreamDebuggingIsEnabled
/// </summary>
public bool RxStreamDebuggingIsEnabled { get; private set; }
/// <summary>
/// Sets the debugging setting for the specified number of minutes
/// </summary>
/// <param name="setting"></param>
/// <param name="minutes"></param>
public void SetDebuggingWithSpecificTimeout(eStreamDebuggingSetting setting, uint minutes)
{
if (setting == eStreamDebuggingSetting.Off)
/// <summary>
/// Indicates that transmit stream debugging is enabled
/// </summary>
public bool TxStreamDebuggingIsEnabled { get; private set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="parentDeviceKey"></param>
public CommunicationStreamDebugging(string parentDeviceKey)
{
DisableDebugging();
return;
ParentDeviceKey = parentDeviceKey;
}
_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);
}
/// <summary>
/// Disabled debugging
/// </summary>
private void DisableDebugging()
{
StopDebugTimer();
Debug.SetDeviceDebugSettings(ParentDeviceKey, eStreamDebuggingSetting.Off);
}
private void StopDebugTimer()
{
RxStreamDebuggingIsEnabled = false;
TxStreamDebuggingIsEnabled = false;
if (DebugExpiryPeriod == null)
/// <summary>
/// Sets the debugging setting and if not setting to off, assumes the default of 30 mintues
/// </summary>
/// <param name="setting"></param>
/// <summary>
/// SetDebuggingWithDefaultTimeout method
/// </summary>
public void SetDebuggingWithDefaultTimeout(eStreamDebuggingSetting setting)
{
return;
if (setting == eStreamDebuggingSetting.Off)
{
DisableDebugging();
return;
}
SetDebuggingWithSpecificTimeout(setting, _DefaultDebugTimeoutMin);
}
DebugExpiryPeriod.Stop();
DebugExpiryPeriod.Dispose();
DebugExpiryPeriod = null;
/// <summary>
/// Sets the debugging setting for the specified number of minutes
/// </summary>
/// <param name="setting"></param>
/// <param name="minutes"></param>
/// <summary>
/// SetDebuggingWithSpecificTimeout method
/// </summary>
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);
}
/// <summary>
/// Disabled debugging
/// </summary>
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;
}
}
}
/// <summary>
/// The available settings for stream debugging
/// </summary>
[Flags]
public enum eStreamDebuggingSetting
{
/// <summary>
/// Debug off
/// </summary>
Off = 0,
/// <summary>
/// Debug received data
/// </summary>
Rx = 1,
/// <summary>
/// Debug transmitted data
/// </summary>
Tx = 2,
/// <summary>
/// Debug both received and transmitted data
/// </summary>
Both = Rx | Tx
}
/// <summary>
/// The available settings for stream debugging response types
/// </summary>
[Flags]
public enum eStreamDebuggingDataTypeSettings
{
/// <summary>
/// Debug data in byte format
/// </summary>
Bytes = 0,
/// <summary>
/// Debug data in text format
/// </summary>
Text = 1,
/// <summary>
/// Debug data in both byte and text formats
/// </summary>
Both = Bytes | Text,
}

View File

@@ -3,90 +3,91 @@ using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace PepperDash.Core;
/// <summary>
/// Config properties that indicate how to communicate with a device for control
/// </summary>
public class ControlPropertiesConfig
namespace PepperDash.Core
{
/// <summary>
/// The method of control
/// Represents a ControlPropertiesConfig
/// </summary>
[JsonProperty("method")]
[JsonConverter(typeof(StringEnumConverter))]
public eControlMethod Method { get; set; }
public class ControlPropertiesConfig
{
/// <summary>
/// The method of control
/// </summary>
[JsonProperty("method")]
[JsonConverter(typeof(StringEnumConverter))]
public eControlMethod Method { get; set; }
/// <summary>
/// The key of the device that contains the control port
/// </summary>
[JsonProperty("controlPortDevKey", NullValueHandling = NullValueHandling.Ignore)]
public string ControlPortDevKey { get; set; }
/// <summary>
/// The key of the device that contains the control port
/// </summary>
[JsonProperty("controlPortDevKey", NullValueHandling = NullValueHandling.Ignore)]
public string ControlPortDevKey { get; set; }
/// <summary>
/// The number of the control port on the device specified by ControlPortDevKey
/// </summary>
[JsonProperty("controlPortNumber", NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value
public uint? ControlPortNumber { get; set; }
/// <summary>
/// The number of the control port on the device specified by ControlPortDevKey
/// </summary>
[JsonProperty("controlPortNumber", NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value
public uint? ControlPortNumber { get; set; }
/// <summary>
/// The name of the control port on the device specified by ControlPortDevKey
/// </summary>
[JsonProperty("controlPortName", NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value
public string ControlPortName { get; set; }
/// <summary>
/// The name of the control port on the device specified by ControlPortDevKey
/// </summary>
[JsonProperty("controlPortName", NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value
public string ControlPortName { get; set; }
/// <summary>
/// Properties for ethernet based communications
/// </summary>
[JsonProperty("tcpSshProperties", NullValueHandling = NullValueHandling.Ignore)]
public TcpSshPropertiesConfig TcpSshProperties { get; set; }
/// <summary>
/// Properties for ethernet based communications
/// </summary>
[JsonProperty("tcpSshProperties", NullValueHandling = NullValueHandling.Ignore)]
public TcpSshPropertiesConfig TcpSshProperties { get; set; }
/// <summary>
/// The filename and path for the IR file
/// </summary>
[JsonProperty("irFile", NullValueHandling = NullValueHandling.Ignore)]
public string IrFile { get; set; }
/// <summary>
/// The filename and path for the IR file
/// </summary>
[JsonProperty("irFile", NullValueHandling = NullValueHandling.Ignore)]
public string IrFile { get; set; }
/// <summary>
/// The IpId of a Crestron device
/// </summary>
[JsonProperty("ipId", NullValueHandling = NullValueHandling.Ignore)]
public string IpId { get; set; }
/// <summary>
/// The IpId of a Crestron device
/// </summary>
[JsonProperty("ipId", NullValueHandling = NullValueHandling.Ignore)]
public string IpId { get; set; }
/// <summary>
/// Readonly uint representation of the IpId
/// </summary>
[JsonIgnore]
public uint IpIdInt { get { return Convert.ToUInt32(IpId, 16); } }
/// <summary>
/// Readonly uint representation of the IpId
/// </summary>
[JsonIgnore]
public uint IpIdInt { get { return Convert.ToUInt32(IpId, 16); } }
/// <summary>
/// Char indicating end of line
/// </summary>
[JsonProperty("endOfLineChar", NullValueHandling = NullValueHandling.Ignore)]
public char EndOfLineChar { get; set; }
/// <summary>
/// Char indicating end of line
/// </summary>
[JsonProperty("endOfLineChar", NullValueHandling = NullValueHandling.Ignore)]
public char EndOfLineChar { get; set; }
/// <summary>
/// Defaults to Environment.NewLine;
/// </summary>
[JsonProperty("endOfLineString", NullValueHandling = NullValueHandling.Ignore)]
public string EndOfLineString { get; set; }
/// <summary>
/// Defaults to Environment.NewLine;
/// </summary>
[JsonProperty("endOfLineString", NullValueHandling = NullValueHandling.Ignore)]
public string EndOfLineString { get; set; }
/// <summary>
/// Indicates
/// </summary>
[JsonProperty("deviceReadyResponsePattern", NullValueHandling = NullValueHandling.Ignore)]
public string DeviceReadyResponsePattern { get; set; }
/// <summary>
/// Indicates
/// </summary>
[JsonProperty("deviceReadyResponsePattern", NullValueHandling = NullValueHandling.Ignore)]
public string DeviceReadyResponsePattern { get; set; }
/// <summary>
/// Used when communcating to programs running in VC-4
/// </summary>
[JsonProperty("roomId", NullValueHandling = NullValueHandling.Ignore)]
public string RoomId { get; set; }
/// <summary>
/// Used when communcating to programs running in VC-4
/// </summary>
[JsonProperty("roomId", NullValueHandling = NullValueHandling.Ignore)]
public string RoomId { get; set; }
/// <summary>
/// Constructor
/// </summary>
public ControlPropertiesConfig()
{
/// <summary>
/// Constructor
/// </summary>
public ControlPropertiesConfig()
{
}
}
}

View File

@@ -16,28 +16,28 @@ using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets;
namespace PepperDash.Core;
/// <summary>
/// Delegate for notifying of socket status changes
/// </summary>
/// <param name="client"></param>
public delegate void GenericSocketStatusChangeEventDelegate(ISocketStatus client);
/// <summary>
/// EventArgs class for socket status changes
/// </summary>
public class GenericSocketStatusChageEventArgs : EventArgs
{
namespace PepperDash.Core
{
/// <summary>
///
/// </summary>
public ISocketStatus Client { get; private set; }
/// <summary>
///
/// Delegate for notifying of socket status changes
/// </summary>
/// <param name="client"></param>
public delegate void GenericSocketStatusChangeEventDelegate(ISocketStatus client);
/// <summary>
/// EventArgs class for socket status changes
/// </summary>
public class GenericSocketStatusChageEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the Client
/// </summary>
public ISocketStatus Client { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="client"></param>
public GenericSocketStatusChageEventArgs(ISocketStatus client)
{
Client = client;
@@ -46,105 +46,105 @@ public delegate void GenericSocketStatusChangeEventDelegate(ISocketStatus client
/// S+ Constructor
/// </summary>
public GenericSocketStatusChageEventArgs() { }
}
/// <summary>
/// Delegate for notifying of TCP Server state changes
/// </summary>
/// <param name="state"></param>
public delegate void GenericTcpServerStateChangedEventDelegate(ServerState state);
/// <summary>
/// EventArgs class for TCP Server state changes
/// </summary>
public class GenericTcpServerStateChangedEventArgs : EventArgs
{
/// <summary>
///
/// </summary>
public ServerState State { get; private set; }
}
/// <summary>
///
/// Delegate for notifying of TCP Server state changes
/// </summary>
/// <param name="state"></param>
public GenericTcpServerStateChangedEventArgs(ServerState state)
public delegate void GenericTcpServerStateChangedEventDelegate(ServerState state);
/// <summary>
/// EventArgs class for TCP Server state changes
/// </summary>
public class GenericTcpServerStateChangedEventArgs : EventArgs
{
State = state;
}
/// <summary>
/// Gets or sets the State
/// </summary>
public ServerState State { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="state"></param>
public GenericTcpServerStateChangedEventArgs(ServerState state)
{
State = state;
}
/// <summary>
/// S+ Constructor
/// </summary>
public GenericTcpServerStateChangedEventArgs() { }
}
/// <summary>
/// Delegate for TCP Server socket status changes
/// </summary>
/// <param name="socket"></param>
/// <param name="clientIndex"></param>
/// <param name="clientStatus"></param>
public delegate void GenericTcpServerSocketStatusChangeEventDelegate(object socket, uint clientIndex, SocketStatus clientStatus);
/// <summary>
/// EventArgs for TCP server socket status changes
/// </summary>
public class GenericTcpServerSocketStatusChangeEventArgs : EventArgs
{
/// <summary>
///
/// </summary>
public object Socket { get; private set; }
/// <summary>
///
/// </summary>
public uint ReceivedFromClientIndex { get; private set; }
/// <summary>
///
/// </summary>
public SocketStatus ClientStatus { get; set; }
/// <summary>
///
/// </summary>
/// <param name="socket"></param>
/// <param name="clientStatus"></param>
public GenericTcpServerSocketStatusChangeEventArgs(object socket, SocketStatus clientStatus)
{
Socket = socket;
ClientStatus = clientStatus;
}
/// <summary>
///
/// Delegate for TCP Server socket status changes
/// </summary>
/// <param name="socket"></param>
/// <param name="clientIndex"></param>
/// <param name="clientStatus"></param>
public GenericTcpServerSocketStatusChangeEventArgs(object socket, uint clientIndex, SocketStatus clientStatus)
public delegate void GenericTcpServerSocketStatusChangeEventDelegate(object socket, uint clientIndex, SocketStatus clientStatus);
/// <summary>
/// EventArgs for TCP server socket status changes
/// </summary>
public class GenericTcpServerSocketStatusChangeEventArgs : EventArgs
{
Socket = socket;
ReceivedFromClientIndex = clientIndex;
ClientStatus = clientStatus;
}
/// <summary>
///
/// </summary>
public object Socket { get; private set; }
/// <summary>
///
/// </summary>
public uint ReceivedFromClientIndex { get; private set; }
/// <summary>
///
/// </summary>
public SocketStatus ClientStatus { get; set; }
/// <summary>
///
/// </summary>
/// <param name="socket"></param>
/// <param name="clientStatus"></param>
public GenericTcpServerSocketStatusChangeEventArgs(object socket, SocketStatus clientStatus)
{
Socket = socket;
ClientStatus = clientStatus;
}
/// <summary>
///
/// </summary>
/// <param name="socket"></param>
/// <param name="clientIndex"></param>
/// <param name="clientStatus"></param>
public GenericTcpServerSocketStatusChangeEventArgs(object socket, uint clientIndex, SocketStatus clientStatus)
{
Socket = socket;
ReceivedFromClientIndex = clientIndex;
ClientStatus = clientStatus;
}
/// <summary>
/// S+ Constructor
/// </summary>
public GenericTcpServerSocketStatusChangeEventArgs() { }
}
/// <summary>
/// EventArgs for TCP server com method receive text
/// </summary>
public class GenericTcpServerCommMethodReceiveTextArgs : EventArgs
{
/// <summary>
///
/// </summary>
public uint ReceivedFromClientIndex { get; private set; }
}
/// <summary>
///
/// EventArgs for TCP server com method receive text
/// </summary>
public class GenericTcpServerCommMethodReceiveTextArgs : EventArgs
{
/// <summary>
///
/// </summary>
public uint ReceivedFromClientIndex { get; private set; }
/// <summary>
///
/// </summary>
public ushort ReceivedFromClientIndexShort
{
get
@@ -153,96 +153,99 @@ public class GenericTcpServerCommMethodReceiveTextArgs : EventArgs
}
}
/// <summary>
///
/// </summary>
public string Text { get; private set; }
/// <summary>
/// Gets or sets the Text
/// </summary>
public string Text { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="text"></param>
public GenericTcpServerCommMethodReceiveTextArgs(string text)
{
Text = text;
}
/// <summary>
///
/// </summary>
/// <param name="text"></param>
public GenericTcpServerCommMethodReceiveTextArgs(string text)
{
Text = text;
}
/// <summary>
///
/// </summary>
/// <param name="text"></param>
/// <param name="clientIndex"></param>
public GenericTcpServerCommMethodReceiveTextArgs(string text, uint clientIndex)
{
Text = text;
ReceivedFromClientIndex = clientIndex;
}
/// <summary>
///
/// </summary>
/// <param name="text"></param>
/// <param name="clientIndex"></param>
public GenericTcpServerCommMethodReceiveTextArgs(string text, uint clientIndex)
{
Text = text;
ReceivedFromClientIndex = clientIndex;
}
/// <summary>
/// S+ Constructor
/// </summary>
public GenericTcpServerCommMethodReceiveTextArgs() { }
}
/// <summary>
/// EventArgs for TCP server client ready for communication
/// </summary>
public class GenericTcpServerClientReadyForcommunicationsEventArgs : EventArgs
{
/// <summary>
///
/// </summary>
public bool IsReady;
/// <summary>
///
/// </summary>
/// <param name="isReady"></param>
public GenericTcpServerClientReadyForcommunicationsEventArgs(bool isReady)
{
IsReady = isReady;
}
/// <summary>
/// EventArgs for TCP server client ready for communication
/// </summary>
public class GenericTcpServerClientReadyForcommunicationsEventArgs : EventArgs
{
/// <summary>
///
/// </summary>
public bool IsReady;
/// <summary>
///
/// </summary>
/// <param name="isReady"></param>
public GenericTcpServerClientReadyForcommunicationsEventArgs(bool isReady)
{
IsReady = isReady;
}
/// <summary>
/// S+ Constructor
/// </summary>
public GenericTcpServerClientReadyForcommunicationsEventArgs() { }
}
/// <summary>
/// EventArgs for UDP connected
/// </summary>
public class GenericUdpConnectedEventArgs : EventArgs
{
/// <summary>
///
/// </summary>
public ushort UConnected;
/// <summary>
///
/// </summary>
public bool Connected;
/// <summary>
/// Constructor
/// </summary>
public GenericUdpConnectedEventArgs() { }
/// <summary>
///
/// </summary>
/// <param name="uconnected"></param>
public GenericUdpConnectedEventArgs(ushort uconnected)
{
UConnected = uconnected;
}
/// <summary>
///
/// EventArgs for UDP connected
/// </summary>
/// <param name="connected"></param>
public GenericUdpConnectedEventArgs(bool connected)
public class GenericUdpConnectedEventArgs : EventArgs
{
Connected = connected;
/// <summary>
///
/// </summary>
public ushort UConnected;
/// <summary>
///
/// </summary>
public bool Connected;
/// <summary>
/// Constructor
/// </summary>
public GenericUdpConnectedEventArgs() { }
/// <summary>
///
/// </summary>
/// <param name="uconnected"></param>
public GenericUdpConnectedEventArgs(ushort uconnected)
{
UConnected = uconnected;
}
/// <summary>
///
/// </summary>
/// <param name="connected"></param>
public GenericUdpConnectedEventArgs(bool connected)
{
Connected = connected;
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -8,388 +8,406 @@ using Crestron.SimplSharp.CrestronSockets;
using Newtonsoft.Json;
using PepperDash.Core.Logging;
namespace PepperDash.Core;
/// <summary>
/// Generic UDP Server device
/// </summary>
public class GenericUdpServer : Device, ISocketStatusWithStreamDebugging
namespace PepperDash.Core
{
private const string SplusKey = "Uninitialized Udp Server";
/// <summary>
/// Object to enable stream debugging
/// Generic UDP Server device
/// </summary>
public CommunicationStreamDebugging StreamDebugging { get; private set; }
/// <summary>
///
/// </summary>
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
public class GenericUdpServer : Device, ISocketStatusWithStreamDebugging
{
private const string SplusKey = "Uninitialized Udp Server";
/// <summary>
/// Object to enable stream debugging
/// </summary>
public CommunicationStreamDebugging StreamDebugging { get; private set; }
/// <summary>
///
/// </summary>
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
/// <summary>
///
/// </summary>
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
/// <summary>
///
/// </summary>
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
/// <summary>
/// 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.
/// </summary>
/// <summary>
/// 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.
/// </summary>
public event EventHandler<GenericUdpReceiveTextExtraArgs> DataRecievedExtra;
/// <summary>
///
/// </summary>
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
/// <summary>
///
/// </summary>
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
/// <summary>
///
/// </summary>
public event EventHandler<GenericUdpConnectedEventArgs> UpdateConnectionStatus;
/// <summary>
///
/// </summary>
public event EventHandler<GenericUdpConnectedEventArgs> UpdateConnectionStatus;
/// <summary>
///
/// </summary>
public SocketStatus ClientStatus
{
get
{
return Server.ServerStatus;
}
}
/// <summary>
///
/// </summary>
public ushort UStatus
{
get { return (ushort)Server.ServerStatus; }
}
/// <summary>
/// Address of server
/// </summary>
public string Hostname { get; set; }
/// <summary>
/// Port on server
/// </summary>
public int Port { get; set; }
/// <summary>
/// Another damn S+ helper because S+ seems to treat large port nums as signed ints
/// which screws up things
/// </summary>
public ushort UPort
{
get { return Convert.ToUInt16(Port); }
set { Port = Convert.ToInt32(value); }
}
/// <summary>
/// Indicates that the UDP Server is enabled
/// </summary>
public bool IsConnected
{
get;
private set;
}
/// <summary>
/// Numeric value indicating
/// </summary>
public ushort UIsConnected
{
get { return IsConnected ? (ushort)1 : (ushort)0; }
}
/// <summary>
/// Defaults to 2000
/// </summary>
public int BufferSize { get; set; }
/// <summary>
/// The server
/// </summary>
public UDPServer Server { get; private set; }
/// <summary>
/// Constructor for S+. Make sure to set key, address, port, and buffersize using init method
/// </summary>
public GenericUdpServer()
: base(SplusKey)
{
StreamDebugging = new CommunicationStreamDebugging(SplusKey);
BufferSize = 5000;
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler);
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="address"></param>
/// <param name="port"></param>
/// <param name="buffefSize"></param>
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);
}
/// <summary>
/// Call from S+ to initialize values
/// </summary>
/// <param name="key"></param>
/// <param name="address"></param>
/// <param name="port"></param>
public void Initialize(string key, string address, ushort port)
{
Key = key;
Hostname = address;
UPort = port;
}
/// <summary>
///
/// </summary>
/// <param name="ethernetEventArgs"></param>
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();
}
}
/// <summary>
///
/// </summary>
/// <param name="programEventType"></param>
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
if (programEventType != eProgramStatusEventType.Stopping)
return;
Debug.Console(1, this, "Program stopping. Disabling Server");
Disconnect();
}
/// <summary>
/// Enables the UDP Server
/// </summary>
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)
/// <summary>
///
/// </summary>
public SocketStatus ClientStatus
{
get
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': Invalid port", Key);
return;
return Server.ServerStatus;
}
}
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);
}
/// <summary>
/// Disabled the UDP Server
/// </summary>
public void Disconnect()
{
if(Server != null)
Server.DisableUDPServer();
IsConnected = false;
var handler = UpdateConnectionStatus;
if (handler != null)
handler(this, new GenericUdpConnectedEventArgs(UIsConnected));
}
/// <summary>
/// Recursive method to receive data
/// </summary>
/// <param name="server"></param>
/// <param name="numBytes"></param>
void Receive(UDPServer server, int numBytes)
{
Debug.Console(2, this, "Received {0} bytes", numBytes);
try
/// <summary>
///
/// </summary>
public ushort UStatus
{
if (numBytes <= 0)
get { return (ushort)Server.ServerStatus; }
}
/// <summary>
/// Address of server
/// </summary>
public string Hostname { get; set; }
/// <summary>
/// Port on server
/// </summary>
public int Port { get; set; }
/// <summary>
/// Another damn S+ helper because S+ seems to treat large port nums as signed ints
/// which screws up things
/// </summary>
public ushort UPort
{
get { return Convert.ToUInt16(Port); }
set { Port = Convert.ToInt32(value); }
}
/// <summary>
/// Indicates that the UDP Server is enabled
/// </summary>
public bool IsConnected
{
get;
private set;
}
/// <summary>
/// Numeric value indicating
/// </summary>
public ushort UIsConnected
{
get { return IsConnected ? (ushort)1 : (ushort)0; }
}
/// <summary>
/// Defaults to 2000
/// </summary>
public int BufferSize { get; set; }
/// <summary>
/// The server
/// </summary>
public UDPServer Server { get; private set; }
/// <summary>
/// Constructor for S+. Make sure to set key, address, port, and buffersize using init method
/// </summary>
public GenericUdpServer()
: base(SplusKey)
{
StreamDebugging = new CommunicationStreamDebugging(SplusKey);
BufferSize = 5000;
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler);
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="address"></param>
/// <param name="port"></param>
/// <param name="bufferSize"></param>
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);
}
/// <summary>
/// Call from S+ to initialize values
/// </summary>
/// <param name="key"></param>
/// <param name="address"></param>
/// <param name="port"></param>
/// <summary>
/// Initialize method
/// </summary>
public void Initialize(string key, string address, ushort port)
{
Key = key;
Hostname = address;
UPort = port;
}
/// <summary>
///
/// </summary>
/// <param name="ethernetEventArgs"></param>
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();
}
}
/// <summary>
///
/// </summary>
/// <param name="programEventType"></param>
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
if (programEventType != eProgramStatusEventType.Stopping)
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);
Debug.Console(1, this, "Program stopping. Disabling Server");
Disconnect();
}
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)
/// <summary>
/// Connect method
/// </summary>
public void Connect()
{
if (Server == null)
{
if (StreamDebugging.RxStreamDebuggingIsEnabled)
try
{
Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length);
var address = IPAddress.Parse(Hostname);
Server = new UDPServer(address, Port, BufferSize);
}
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
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();
}
}
var textHandler = TextReceived;
if (textHandler != null)
if (string.IsNullOrEmpty(Hostname))
{
if (StreamDebugging.RxStreamDebuggingIsEnabled)
Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length);
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
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);
}
/// <summary>
/// Disconnect method
/// </summary>
public void Disconnect()
{
if (Server != null)
Server.DisableUDPServer();
IsConnected = false;
var handler = UpdateConnectionStatus;
if (handler != null)
handler(this, new GenericUdpConnectedEventArgs(UIsConnected));
}
/// <summary>
/// Recursive method to receive data
/// </summary>
/// <param name="server"></param>
/// <param name="numBytes"></param>
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);
}
}
catch (Exception ex)
/// <summary>
/// General send method
/// </summary>
/// <param name="text"></param>
/// <summary>
/// SendText method
/// </summary>
public void SendText(string text)
{
this.LogException(ex, "GenericUdpServer Receive error");
var bytes = Encoding.GetEncoding(28591).GetBytes(text);
if (IsConnected && Server != null)
{
this.PrintSentText(text);
Server.SendData(bytes, bytes.Length);
}
}
finally
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
/// <summary>
/// SendBytes method
/// </summary>
public void SendBytes(byte[] bytes)
{
server.ReceiveDataAsync(Receive);
this.PrintSentBytes(bytes);
if (IsConnected && Server != null)
Server.SendData(bytes, bytes.Length);
}
}
/// <summary>
/// General send method
/// Represents a GenericUdpReceiveTextExtraArgs
/// </summary>
/// <param name="text"></param>
public void SendText(string text)
public class GenericUdpReceiveTextExtraArgs : EventArgs
{
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);
}
}
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
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);
}
}
/// <summary>
///
/// </summary>
public class GenericUdpReceiveTextExtraArgs : EventArgs
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Text { get; private set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string IpAddress { get; private set; }
/// <summary>
///
/// </summary>
public int Port { get; private set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public int Port { get; private set; }
/// <summary>
///
/// </summary>
public byte[] Bytes { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="text"></param>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="bytes"></param>
/// <summary>
///
/// </summary>
/// <param name="text"></param>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="bytes"></param>
public GenericUdpReceiveTextExtraArgs(string text, string ipAddress, int port, byte[] bytes)
{
Text = text;
IpAddress = ipAddress;
Port = port;
Bytes = bytes;
}
{
Text = text;
IpAddress = ipAddress;
Port = port;
Bytes = bytes;
}
/// <summary>
/// Stupid S+ Constructor
/// </summary>
public GenericUdpReceiveTextExtraArgs() { }
}
/// <summary>
///
/// </summary>
public class UdpServerPropertiesConfig
{
/// <summary>
///
/// </summary>
[JsonProperty(Required = Required.Always)]
public string Address { get; set; }
/// <summary>
/// Stupid S+ Constructor
/// </summary>
public GenericUdpReceiveTextExtraArgs() { }
}
/// <summary>
///
/// </summary>
[JsonProperty(Required = Required.Always)]
public int Port { get; set; }
/// <summary>
/// Defaults to 32768
/// </summary>
public int BufferSize { get; set; }
/// <summary>
///
/// </summary>
public UdpServerPropertiesConfig()
public class UdpServerPropertiesConfig
{
BufferSize = 32768;
/// <summary>
///
/// </summary>
[JsonProperty(Required = Required.Always)]
public string Address { get; set; }
/// <summary>
///
/// </summary>
[JsonProperty(Required = Required.Always)]
public int Port { get; set; }
/// <summary>
/// Defaults to 32768
/// </summary>
public int BufferSize { get; set; }
/// <summary>
///
/// </summary>
public UdpServerPropertiesConfig()
{
BufferSize = 32768;
}
}
}

View File

@@ -0,0 +1,69 @@
using System;
using Crestron.SimplSharp;
namespace PepperDash.Core
{
/// <summary>
/// Extension methods for stream debugging
/// </summary>
public static class StreamDebuggingExtensions
{
private static readonly string app = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? $"App {InitialParametersClass.ApplicationNumber}" : $"{InitialParametersClass.RoomId}";
/// <summary>
/// Print the sent bytes to the console
/// </summary>
/// <param name="comms">comms device</param>
/// <param name="bytes">bytes to print</param>
public static void PrintSentBytes(this IStreamDebugging comms, byte[] bytes)
{
if (!comms.StreamDebugging.TxStreamDebuggingIsEnabled) return;
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Sending {bytes.Length} bytes: '{ComTextHelper.GetEscapedText(bytes)}'");
}
/// <summary>
/// Print the received bytes to the console
/// </summary>
/// <param name="comms">comms device</param>
/// <param name="bytes">bytes to print</param>
public static void PrintReceivedBytes(this IStreamDebugging comms, byte[] bytes)
{
if (!comms.StreamDebugging.RxStreamDebuggingIsEnabled) return;
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Received {bytes.Length} bytes: '{ComTextHelper.GetEscapedText(bytes)}'");
}
/// <summary>
/// Print the sent text to the console
/// </summary>
/// <param name="comms">comms device</param>
/// <param name="text">text to print</param>
public static void PrintSentText(this IStreamDebugging comms, string text)
{
if (!comms.StreamDebugging.TxStreamDebuggingIsEnabled) return;
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Sending Text: '{ComTextHelper.GetDebugText(text)}'");
}
/// <summary>
/// Print the received text to the console
/// </summary>
/// <param name="comms">comms device</param>
/// <param name="text">text to print</param>
public static void PrintReceivedText(this IStreamDebugging comms, string text)
{
if (!comms.StreamDebugging.RxStreamDebuggingIsEnabled) return;
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Received Text: '{ComTextHelper.GetDebugText(text)}'");
}
}
}

View File

@@ -1,58 +1,59 @@
using Newtonsoft.Json;
namespace PepperDash.Core;
/// <summary>
/// Client config object for TCP client with server that inherits from TcpSshPropertiesConfig and adds properties for shared key and heartbeat
/// </summary>
public class TcpClientConfigObject
namespace PepperDash.Core
{
/// <summary>
/// TcpSsh Properties
/// Represents a TcpClientConfigObject
/// </summary>
[JsonProperty("control")]
public ControlPropertiesConfig Control { get; set; }
public class TcpClientConfigObject
{
/// <summary>
/// TcpSsh Properties
/// </summary>
[JsonProperty("control")]
public ControlPropertiesConfig Control { get; set; }
/// <summary>
/// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic
/// </summary>
[JsonProperty("secure")]
public bool Secure { get; set; }
/// <summary>
/// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic
/// </summary>
[JsonProperty("secure")]
public bool Secure { get; set; }
/// <summary>
/// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client
/// </summary>
[JsonProperty("sharedKeyRequired")]
public bool SharedKeyRequired { get; set; }
/// <summary>
/// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client
/// </summary>
[JsonProperty("sharedKeyRequired")]
public bool SharedKeyRequired { get; set; }
/// <summary>
/// The shared key that must match on the server and client
/// </summary>
[JsonProperty("sharedKey")]
public string SharedKey { get; set; }
/// <summary>
/// The shared key that must match on the server and client
/// </summary>
[JsonProperty("sharedKey")]
public string SharedKey { get; set; }
/// <summary>
/// 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.
/// </summary>
[JsonProperty("heartbeatRequired")]
public bool HeartbeatRequired { get; set; }
/// <summary>
/// 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.
/// </summary>
[JsonProperty("heartbeatRequired")]
public bool HeartbeatRequired { get; set; }
/// <summary>
/// The interval in seconds for the heartbeat from the client. If not received client is disconnected
/// </summary>
[JsonProperty("heartbeatRequiredIntervalInSeconds")]
public ushort HeartbeatRequiredIntervalInSeconds { get; set; }
/// <summary>
/// The interval in seconds for the heartbeat from the client. If not received client is disconnected
/// </summary>
[JsonProperty("heartbeatRequiredIntervalInSeconds")]
public ushort HeartbeatRequiredIntervalInSeconds { get; set; }
/// <summary>
/// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided.
/// </summary>
[JsonProperty("heartbeatStringToMatch")]
public string HeartbeatStringToMatch { get; set; }
/// <summary>
/// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided.
/// </summary>
[JsonProperty("heartbeatStringToMatch")]
public string HeartbeatStringToMatch { get; set; }
/// <summary>
/// Receive Queue size must be greater than 20 or defaults to 20
/// </summary>
[JsonProperty("receiveQueueSize")]
public int ReceiveQueueSize { get; set; }
/// <summary>
/// Receive Queue size must be greater than 20 or defaults to 20
/// </summary>
[JsonProperty("receiveQueueSize")]
public int ReceiveQueueSize { get; set; }
}
}

View File

@@ -4,56 +4,57 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core;
/// <summary>
/// Tcp Server Config object with properties for a tcp server with shared key and heartbeat capabilities
/// </summary>
public class TcpServerConfigObject
namespace PepperDash.Core
{
/// <summary>
/// Uique key
/// Tcp Server Config object with properties for a tcp server with shared key and heartbeat capabilities
/// </summary>
public string Key { get; set; }
/// <summary>
/// Max Clients that the server will allow to connect.
/// </summary>
public ushort MaxClients { get; set; }
/// <summary>
/// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic
/// </summary>
public bool Secure { get; set; }
/// <summary>
/// Port for the server to listen on
/// </summary>
public int Port { get; set; }
/// <summary>
/// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client
/// </summary>
public bool SharedKeyRequired { get; set; }
/// <summary>
/// The shared key that must match on the server and client
/// </summary>
public string SharedKey { get; set; }
/// <summary>
/// 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.
/// </summary>
public bool HeartbeatRequired { get; set; }
/// <summary>
/// The interval in seconds for the heartbeat from the client. If not received client is disconnected
/// </summary>
public ushort HeartbeatRequiredIntervalInSeconds { get; set; }
/// <summary>
/// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided.
/// </summary>
public string HeartbeatStringToMatch { get; set; }
/// <summary>
/// Client buffer size. See Crestron help. defaults to 2000 if not greater than 2000
/// </summary>
public int BufferSize { get; set; }
/// <summary>
/// Receive Queue size must be greater than 20 or defaults to 20
/// </summary>
public int ReceiveQueueSize { get; set; }
public class TcpServerConfigObject
{
/// <summary>
/// Uique key
/// </summary>
public string Key { get; set; }
/// <summary>
/// Max Clients that the server will allow to connect.
/// </summary>
public ushort MaxClients { get; set; }
/// <summary>
/// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic
/// </summary>
public bool Secure { get; set; }
/// <summary>
/// Port for the server to listen on
/// </summary>
public int Port { get; set; }
/// <summary>
/// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client
/// </summary>
public bool SharedKeyRequired { get; set; }
/// <summary>
/// The shared key that must match on the server and client
/// </summary>
public string SharedKey { get; set; }
/// <summary>
/// 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.
/// </summary>
public bool HeartbeatRequired { get; set; }
/// <summary>
/// The interval in seconds for the heartbeat from the client. If not received client is disconnected
/// </summary>
public ushort HeartbeatRequiredIntervalInSeconds { get; set; }
/// <summary>
/// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided.
/// </summary>
public string HeartbeatStringToMatch { get; set; }
/// <summary>
/// Client buffer size. See Crestron help. defaults to 2000 if not greater than 2000
/// </summary>
public int BufferSize { get; set; }
/// <summary>
/// Receive Queue size must be greater than 20 or defaults to 20
/// </summary>
public int ReceiveQueueSize { get; set; }
}
}

View File

@@ -4,75 +4,84 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core;
/// <summary>
/// Crestron Control Methods for a comm object
/// </summary>
public enum eControlMethod
namespace PepperDash.Core
{
/// <summary>
///
/// Crestron Control Methods for a comm object
/// </summary>
None = 0,
/// <summary>
/// RS232/422/485
/// </summary>
Com,
/// <summary>
/// Crestron IpId (most Crestron ethernet devices)
/// </summary>
IpId,
/// <summary>
/// Crestron IpIdTcp (HD-MD series, etc.)
/// </summary>
IpidTcp,
/// <summary>
/// Crestron IR control
/// </summary>
IR,
/// <summary>
/// SSH client
/// </summary>
Ssh,
/// <summary>
/// TCP/IP client
/// </summary>
Tcpip,
/// <summary>
/// Telnet
/// </summary>
Telnet,
/// <summary>
/// Crestnet device
/// </summary>
Cresnet,
/// <summary>
/// CEC Control, via a DM HDMI port
/// </summary>
Cec,
/// <summary>
/// UDP Server
/// </summary>
Udp,
/// <summary>
/// HTTP client
/// </summary>
Http,
/// <summary>
/// HTTPS client
/// </summary>
Https,
/// <summary>
/// Websocket client
/// </summary>
Ws,
/// <summary>
/// Secure Websocket client
/// </summary>
Wss,
/// <summary>
/// Secure TCP/IP
/// </summary>
SecureTcpIp
public enum eControlMethod
{
/// <summary>
///
/// </summary>
None = 0,
/// <summary>
/// RS232/422/485
/// </summary>
Com,
/// <summary>
/// Crestron IpId (most Crestron ethernet devices)
/// </summary>
IpId,
/// <summary>
/// Crestron IpIdTcp (HD-MD series, etc.)
/// </summary>
IpidTcp,
/// <summary>
/// Crestron IR control
/// </summary>
IR,
/// <summary>
/// SSH client
/// </summary>
Ssh,
/// <summary>
/// TCP/IP client
/// </summary>
Tcpip,
/// <summary>
/// Telnet
/// </summary>
Telnet,
/// <summary>
/// Crestnet device
/// </summary>
Cresnet,
/// <summary>
/// CEC Control, via a DM HDMI port
/// </summary>
Cec,
/// <summary>
/// UDP Server
/// </summary>
Udp,
/// <summary>
/// HTTP client
/// </summary>
Http,
/// <summary>
/// HTTPS client
/// </summary>
Https,
/// <summary>
/// Websocket client
/// </summary>
Ws,
/// <summary>
/// Secure Websocket client
/// </summary>
Wss,
/// <summary>
/// Secure TCP/IP
/// </summary>
SecureTcpIp,
/// <summary>
/// Used when comms needs to be handled in SIMPL and bridged opposite the normal direction
/// </summary>
ComBridge,
/// <summary>
/// InfinetEX control
/// </summary>
InfinetEx
}
}

View File

@@ -0,0 +1,24 @@
using System;
namespace PepperDash.Core
{
/// <summary>
/// The available settings for stream debugging data format types
/// </summary>
[Flags]
public enum eStreamDebuggingDataTypeSettings
{
/// <summary>
/// Debug data in byte format
/// </summary>
Bytes = 0,
/// <summary>
/// Debug data in text format
/// </summary>
Text = 1,
/// <summary>
/// Debug data in both byte and text formats
/// </summary>
Both = Bytes | Text
}
}

View File

@@ -0,0 +1,28 @@
using System;
namespace PepperDash.Core
{
/// <summary>
/// The available settings for stream debugging
/// </summary>
[Flags]
public enum eStreamDebuggingSetting
{
/// <summary>
/// Debug off
/// </summary>
Off = 0,
/// <summary>
/// Debug received data
/// </summary>
Rx = 1,
/// <summary>
/// Debug transmitted data
/// </summary>
Tx = 2,
/// <summary>
/// Debug both received and transmitted data
/// </summary>
Both = Rx | Tx
}
}

View File

@@ -1,246 +1,205 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
namespace PepperDash.Core;
/// <summary>
/// An incoming communication stream
/// </summary>
public interface ICommunicationReceiver : IKeyed
namespace PepperDash.Core
{
/// <summary>
/// Notifies of bytes received
/// An incoming communication stream
/// </summary>
event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
/// <summary>
/// Notifies of text received
/// </summary>
event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
public interface ICommunicationReceiver : IKeyed
{
/// <summary>
/// Notifies of bytes received
/// </summary>
event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
/// <summary>
/// Notifies of text received
/// </summary>
event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
/// <summary>
/// Indicates connection status
/// </summary>
[JsonProperty("isConnected")]
bool IsConnected { get; }
/// <summary>
/// Connect to the device
/// </summary>
void Connect();
/// <summary>
/// Disconnect from the device
/// </summary>
void Disconnect();
}
/// <summary>
/// Indicates connection status
/// Defines the contract for IBasicCommunication
/// </summary>
[JsonProperty("isConnected")]
bool IsConnected { get; }
/// <summary>
/// Connect to the device
/// </summary>
void Connect();
/// <summary>
/// Disconnect from the device
/// </summary>
void Disconnect();
}
/// <summary>
/// Represents a device that uses basic connection
/// </summary>
public interface IBasicCommunication : ICommunicationReceiver
{
/// <summary>
/// Send text to the device
/// </summary>
/// <param name="text"></param>
public interface IBasicCommunication : ICommunicationReceiver
{
/// <summary>
/// Send text to the device
/// </summary>
/// <param name="text"></param>
void SendText(string text);
/// <summary>
/// Send bytes to the device
/// </summary>
/// <param name="bytes"></param>
/// <summary>
/// Send bytes to the device
/// </summary>
/// <param name="bytes"></param>
void SendBytes(byte[] bytes);
}
}
/// <summary>
/// Represents a device that implements IBasicCommunication and IStreamDebugging
/// </summary>
public interface IBasicCommunicationWithStreamDebugging : IBasicCommunication, IStreamDebugging
{
}
/// <summary>
/// Represents a device with stream debugging capablities
/// </summary>
public interface IStreamDebugging
{
/// <summary>
/// Object to enable stream debugging
/// Represents a device that implements IBasicCommunication and IStreamDebugging
/// </summary>
[JsonProperty("streamDebugging")]
CommunicationStreamDebugging StreamDebugging { get; }
}
public interface IBasicCommunicationWithStreamDebugging : IBasicCommunication, IStreamDebugging
{
}
/// <summary>
/// For IBasicCommunication classes that have SocketStatus. GenericSshClient,
/// GenericTcpIpClient
/// </summary>
public interface ISocketStatus : IBasicCommunication
{
/// <summary>
/// Notifies of socket status changes
/// Represents a device with stream debugging capablities
/// </summary>
public interface IStreamDebugging : IKeyed
{
/// <summary>
/// Object to enable stream debugging
/// </summary>
[JsonProperty("streamDebugging")]
CommunicationStreamDebugging StreamDebugging { get; }
}
/// <summary>
/// For IBasicCommunication classes that have SocketStatus. GenericSshClient,
/// GenericTcpIpClient
/// </summary>
public interface ISocketStatus : IBasicCommunication
{
/// <summary>
/// Notifies of socket status changes
/// </summary>
event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
/// <summary>
/// The current socket status of the client
/// </summary>
[JsonProperty("clientStatus")]
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
SocketStatus ClientStatus { get; }
}
/// <summary>
/// The current socket status of the client
/// Describes a device that implements ISocketStatus and IStreamDebugging
/// </summary>
[JsonProperty("clientStatus")]
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
SocketStatus ClientStatus { get; }
}
public interface ISocketStatusWithStreamDebugging : ISocketStatus, IStreamDebugging
{
/// <summary>
/// Describes a device that implements ISocketStatus and IStreamDebugging
/// </summary>
public interface ISocketStatusWithStreamDebugging : ISocketStatus, IStreamDebugging
{
}
}
/// <summary>
/// Describes a device that can automatically attempt to reconnect
/// </summary>
/// <summary>
/// Describes a device that can automatically attempt to reconnect
/// </summary>
public interface IAutoReconnect
{
/// <summary>
/// Enable automatic recconnect
/// </summary>
[JsonProperty("autoReconnect")]
bool AutoReconnect { get; set; }
/// <summary>
/// Interval in ms to attempt automatic recconnections
/// </summary>
[JsonProperty("autoReconnectIntervalMs")]
int AutoReconnectIntervalMs { get; set; }
}
{
/// <summary>
/// Enable automatic recconnect
/// </summary>
[JsonProperty("autoReconnect")]
bool AutoReconnect { get; set; }
/// <summary>
/// Interval in ms to attempt automatic recconnections
/// </summary>
[JsonProperty("autoReconnectIntervalMs")]
int AutoReconnectIntervalMs { get; set; }
}
/// <summary>
///
/// </summary>
public enum eGenericCommMethodStatusChangeType
{
/// <summary>
/// Connected
///
/// </summary>
public enum eGenericCommMethodStatusChangeType
{
/// <summary>
/// Connected
/// </summary>
Connected,
/// <summary>
/// Disconnected
/// </summary>
Disconnected
}
/// <summary>
/// Disconnected
/// </summary>
Disconnected
}
/// <summary>
/// This delegate defines handler for IBasicCommunication status changes
/// </summary>
/// <param name="comm">Device firing the status change</param>
/// <param name="status"></param>
public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status);
/// <summary>
///
/// </summary>
public class GenericCommMethodReceiveBytesArgs : EventArgs
{
/// <summary>
///
/// This delegate defines handler for IBasicCommunication status changes
/// </summary>
public byte[] Bytes { get; private set; }
/// <param name="comm">Device firing the status change</param>
/// <param name="status"></param>
public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status);
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
public class GenericCommMethodReceiveBytesArgs : EventArgs
{
/// <summary>
/// Gets or sets the Bytes
/// </summary>
public byte[] Bytes { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
public GenericCommMethodReceiveBytesArgs(byte[] bytes)
{
Bytes = bytes;
}
{
Bytes = bytes;
}
/// <summary>
/// S+ Constructor
/// </summary>
public GenericCommMethodReceiveBytesArgs() { }
}
/// <summary>
/// S+ Constructor
/// </summary>
public GenericCommMethodReceiveBytesArgs() { }
}
/// <summary>
///
/// </summary>
public class GenericCommMethodReceiveTextArgs : EventArgs
{
/// <summary>
///
/// </summary>
public class GenericCommMethodReceiveTextArgs : EventArgs
{
/// <summary>
///
/// </summary>
public string Text { get; private set; }
/// <summary>
///
/// </summary>
public string Delimiter { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="text"></param>
/// <summary>
///
/// </summary>
public string Delimiter { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="text"></param>
public GenericCommMethodReceiveTextArgs(string text)
{
Text = text;
}
{
Text = text;
}
/// <summary>
///
/// </summary>
/// <param name="text"></param>
/// <param name="delimiter"></param>
public GenericCommMethodReceiveTextArgs(string text, string delimiter)
:this(text)
{
Delimiter = delimiter;
/// <summary>
///
/// </summary>
/// <param name="text"></param>
/// <param name="delimiter"></param>
public GenericCommMethodReceiveTextArgs(string text, string delimiter)
: this(text)
{
Delimiter = delimiter;
}
/// <summary>
/// S+ Constructor
/// </summary>
public GenericCommMethodReceiveTextArgs() { }
}
/// <summary>
/// S+ Constructor
/// </summary>
public GenericCommMethodReceiveTextArgs() { }
}
/// <summary>
///
/// </summary>
public class ComTextHelper
{
/// <summary>
/// Gets escaped text for a byte array
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static string GetEscapedText(byte[] bytes)
{
return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray());
}
/// <summary>
/// Gets escaped text for a string
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
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());
}
/// <summary>
/// Gets debug text for a string
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static string GetDebugText(string text)
{
return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value));
}
}
}

View File

@@ -7,42 +7,61 @@ using Newtonsoft.Json.Linq;
using PepperDash.Core;
using Serilog.Events;
namespace PepperDash.Core.Config;
namespace PepperDash.Core.Config
{
/// <summary>
/// Reads a Portal formatted config file
/// </summary>
/// <summary>
/// Reads a Portal formatted config file
/// </summary>
public class PortalConfigReader
{
/// <summary>
/// Reads the config file, checks if it needs a merge, merges and saves, then returns the merged Object.
/// </summary>
/// <returns>JObject of config file</returns>
public static void ReadAndMergeFileIfNecessary(string filePath, string savePath)
const string template = "template";
const string system = "system";
const string systemUrl = "system_url";
const string templateUrl = "template_url";
const string info = "info";
const string devices = "devices";
const string rooms = "rooms";
const string sourceLists = "sourceLists";
const string destinationLists = "destinationLists";
const string cameraLists = "cameraLists";
const string audioControlPointLists = "audioControlPointLists";
const string tieLines = "tieLines";
const string joinMaps = "joinMaps";
const string global = "global";
/// <summary>
/// Reads the config file, checks if it needs a merge, merges and saves, then returns the merged Object.
/// </summary>
/// <returns>JObject of config file</returns>
public static void ReadAndMergeFileIfNecessary(string filePath, string savePath)
{
try
{
if (!File.Exists(filePath))
{
Debug.Console(1, Debug.ErrorLogLevel.Error,
Debug.LogError(
"ERROR: Configuration file not present. Please load file to {0} and reset program", filePath);
}
using (StreamReader fs = new StreamReader(filePath))
{
var jsonObj = JObject.Parse(fs.ReadToEnd());
if(jsonObj["template"] != null && jsonObj["system"] != null)
if(jsonObj[template] != null && jsonObj[system] != null)
{
// it's a double-config, merge it.
var merged = MergeConfigs(jsonObj);
if (jsonObj["system_url"] != null)
if (jsonObj[systemUrl] != null)
{
merged["systemUrl"] = jsonObj["system_url"].Value<string>();
merged[systemUrl] = jsonObj[systemUrl].Value<string>();
}
if (jsonObj["template_url"] != null)
if (jsonObj[templateUrl] != null)
{
merged["templateUrl"] = jsonObj["template_url"].Value<string>();
merged[templateUrl] = jsonObj[templateUrl].Value<string>();
}
jsonObj = merged;
@@ -67,6 +86,9 @@ namespace PepperDash.Core.Config;
/// </summary>
/// <param name="doubleConfig"></param>
/// <returns></returns>
/// <summary>
/// MergeConfigs method
/// </summary>
public static JObject MergeConfigs(JObject doubleConfig)
{
var system = JObject.FromObject(doubleConfig["system"]);
@@ -74,62 +96,62 @@ namespace PepperDash.Core.Config;
var merged = new JObject();
// Put together top-level objects
if (system["info"] != null)
merged.Add("info", Merge(template["info"], system["info"], "infO"));
if (system[info] != null)
merged.Add(info, Merge(template[info], system[info], info));
else
merged.Add("info", template["info"]);
merged.Add(info, template[info]);
merged.Add("devices", MergeArraysOnTopLevelProperty(template["devices"] as JArray,
system["devices"] as JArray, "key", "devices"));
merged.Add(devices, MergeArraysOnTopLevelProperty(template[devices] as JArray,
system[devices] as JArray, "key", devices));
if (system["rooms"] == null)
merged.Add("rooms", template["rooms"]);
if (system[rooms] == null)
merged.Add(rooms, template[rooms]);
else
merged.Add("rooms", MergeArraysOnTopLevelProperty(template["rooms"] as JArray,
system["rooms"] as JArray, "key", "rooms"));
merged.Add(rooms, MergeArraysOnTopLevelProperty(template[rooms] as JArray,
system[rooms] as JArray, "key", rooms));
if (system["sourceLists"] == null)
merged.Add("sourceLists", template["sourceLists"]);
if (system[sourceLists] == null)
merged.Add(sourceLists, template[sourceLists]);
else
merged.Add("sourceLists", Merge(template["sourceLists"], system["sourceLists"], "sourceLists"));
merged.Add(sourceLists, Merge(template[sourceLists], system[sourceLists], sourceLists));
if (system["destinationLists"] == null)
merged.Add("destinationLists", template["destinationLists"]);
if (system[destinationLists] == null)
merged.Add(destinationLists, template[destinationLists]);
else
merged.Add("destinationLists",
Merge(template["destinationLists"], system["destinationLists"], "destinationLists"));
merged.Add(destinationLists,
Merge(template[destinationLists], system[destinationLists], destinationLists));
if (system["cameraLists"] == null)
merged.Add("cameraLists", template["cameraLists"]);
else
merged.Add("cameraLists", Merge(template["cameraLists"], system["cameraLists"], "cameraLists"));
if (system[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());
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"));
if (system[global] != null)
merged.Add(global, Merge(template[global], system[global], global));
else
merged.Add("global", template["global"]);
merged.Add(global, template[global]);
//Debug.Console(2, "MERGED CONFIG RESULT: \x0d\x0a{0}", merged);
return merged;
@@ -147,26 +169,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
{
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<int>("uid") == tmplDev.Value<int>("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);
if (a2[0]["key"] == null) // If the first item in the system array has no key, overwrite the template array
{ // with the system array
return a2;
}
else // The arrays are keyed, merge them by key
{
for (int i = 0; i < a1.Count(); i++)
{
var a1Dev = a1[i];
// Try to get a system device and if found, merge it onto template
var a2Match = a2.FirstOrDefault(t => t[propertyName].Equals(a1Dev[propertyName]));// t.Value<int>("uid") == tmplDev.Value<int>("uid"));
if (a2Match != null)
{
var mergedItem = Merge(a1Dev, a2Match, string.Format("{0}[{1}].", path, i));// Merge(JObject.FromObject(a1Dev), JObject.FromObject(a2Match));
result.Add(mergedItem);
}
else
result.Add(a1Dev);
}
}
}
}
return result;
}
@@ -183,9 +205,9 @@ namespace PepperDash.Core.Config;
/// <summary>
/// Merge o2 onto o1
/// </summary>
/// <param name="o1"></param>
/// <param name="o2"></param>
/// <param name="path"></param>
/// <param name="o1"></param>
/// <param name="o2"></param>
/// <param name="path"></param>
static JObject Merge(JObject o1, JObject o2, string path)
{
foreach (var o2Prop in o2)
@@ -225,10 +247,11 @@ namespace PepperDash.Core.Config;
}
catch (Exception e)
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "Cannot merge items at path {0}: \r{1}", propPath, e);
Debug.LogError($"Cannot merge items at path {propPath}: \r{e}");
}
}
}
return o1;
}
}
}
}

View File

@@ -4,18 +4,28 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core;
public class EncodingHelper
namespace PepperDash.Core
{
public static string ConvertUtf8ToAscii(string utf8String)
/// <summary>
/// Represents a EncodingHelper
/// </summary>
public class EncodingHelper
{
return Encoding.ASCII.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length);
}
/// <summary>
/// ConvertUtf8ToAscii method
/// </summary>
public static string ConvertUtf8ToAscii(string utf8String)
{
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);
}
/// <summary>
/// ConvertUtf8ToUtf16 method
/// </summary>
public static string ConvertUtf8ToUtf16(string utf8String)
{
return Encoding.Unicode.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length);
}
}
}

View File

@@ -6,28 +6,30 @@ using Crestron.SimplSharp;
using Newtonsoft.Json;
using Serilog;
namespace PepperDash.Core;
/// <summary>
/// Unique key interface to require a unique key for the class
/// </summary>
namespace PepperDash.Core
{
/// <summary>
/// Unique key interface to require a unique key for the class
/// </summary>
public interface IKeyed
{
/// <summary>
/// Gets the unique key associated with the object.
/// </summary>
[JsonProperty("key")]
/// <summary>
/// Unique Key
/// </summary>
[JsonProperty("key")]
string Key { get; }
}
}
/// <summary>
/// Named Keyed device interface. Forces the device to have a Unique Key and a name.
/// </summary>
public interface IKeyName : IKeyed
{
/// <summary>
/// Gets the name associated with the current object.
/// <summary>
/// Named Keyed device interface. Forces the device to have a Unique Key and a name.
/// </summary>
[JsonProperty("name")]
public interface IKeyName : IKeyed
{
/// <summary>
/// Isn't it obvious :)
/// </summary>
[JsonProperty("name")]
string Name { get; }
}
}

View File

@@ -2,12 +2,12 @@
using System.Collections.Generic;
using Serilog.Events;
namespace PepperDash.Core;
namespace PepperDash.Core
{
//*********************************************************************************************************
/// <summary>
/// The core event and status-bearing class that most if not all device and connectors can derive from.
/// </summary>
/// <summary>
/// Represents a Device
/// </summary>
public class Device : IKeyName
{
@@ -15,23 +15,23 @@ namespace PepperDash.Core;
/// Unique Key
/// </summary>
public string Key { get; protected set; }
/// <summary>
/// Name of the devie
/// </summary>
/// <summary>
/// Gets or sets the Name
/// </summary>
public string Name { get; protected set; }
/// <summary>
///
/// </summary>
public bool Enabled { get; protected set; }
///// <summary>
///// 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.
///// </summary>
/// <summary>
/// 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.
/// </summary>
//public DeviceConfig Config { get; private set; }
///// <summary>
///// Helper method to check if Config exists
///// </summary>
/// <summary>
/// Helper method to check if Config exists
/// </summary>
//public bool HasConfig { get { return Config != null; } }
List<Action> _PreActivationActions;
@@ -86,6 +86,9 @@ namespace PepperDash.Core;
/// Adds a post activation action
/// </summary>
/// <param name="act"></param>
/// <summary>
/// AddPostActivationAction method
/// </summary>
public void AddPostActivationAction(Action act)
{
if (_PostActivationActions == null)
@@ -93,9 +96,9 @@ namespace PepperDash.Core;
_PostActivationActions.Add(act);
}
/// <summary>
/// Executes the preactivation actions
/// </summary>
/// <summary>
/// PreActivate method
/// </summary>
public void PreActivate()
{
if (_PreActivationActions != null)
@@ -112,11 +115,9 @@ namespace PepperDash.Core;
});
}
/// <summary>
/// Gets this device ready to be used in the system. Runs any added pre-activation items, and
/// all post-activation at end. Classes needing additional logic to
/// run should override CustomActivate()
/// </summary>
/// <summary>
/// Activate method
/// </summary>
public bool Activate()
{
//if (_PreActivationActions != null)
@@ -127,9 +128,9 @@ namespace PepperDash.Core;
return result;
}
/// <summary>
/// Executes the postactivation actions
/// </summary>
/// <summary>
/// PostActivate method
/// </summary>
public void PostActivate()
{
if (_PostActivationActions != null)
@@ -152,6 +153,9 @@ namespace PepperDash.Core;
/// do not need to call base.CustomActivate()
/// </summary>
/// <returns>true if device activated successfully.</returns>
/// <summary>
/// CustomActivate method
/// </summary>
public virtual bool CustomActivate() { return true; }
/// <summary>
@@ -178,14 +182,18 @@ namespace PepperDash.Core;
if (o is bool && !(bool)o) a();
}
/// <summary>
/// Returns a string representation of the object, including its key and name.
/// </summary>
/// <remarks>The returned string is formatted as "{Key} - {Name}". If the <c>Name</c> property is
/// null or empty, "---" is used in place of the name.</remarks>
/// <returns>A string that represents the object, containing the key and name in the format "{Key} - {Name}".</returns>
/// <summary>
/// Returns a string representation of the object, including its key and name.
/// </summary>
/// <remarks>The returned string is formatted as "{Key} - {Name}". If the <c>Name</c> property is
/// null or empty, "---" is used in place of the name.</remarks>
/// <returns>A string that represents the object, containing the key and name in the format "{Key} - {Name}".</returns>
/// <summary>
/// ToString method
/// </summary>
public override string ToString()
{
return string.Format("{0} - {1}", Key, string.IsNullOrEmpty(Name) ? "---" : Name);
}
}
}
}

View File

@@ -2,11 +2,11 @@
using Newtonsoft.Json;
using Serilog.Events;
namespace PepperDash.Core;
/// <summary>
/// Class to help with accessing values from the CrestronEthernetHelper class
/// </summary>
namespace PepperDash.Core
{
/// <summary>
/// Represents a EthernetHelper
/// </summary>
public class EthernetHelper
{
/// <summary>
@@ -24,9 +24,9 @@ namespace PepperDash.Core;
// ADD OTHER HELPERS HERE
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the PortNumber
/// </summary>
public int PortNumber { get; private set; }
private EthernetHelper(int portNumber)
@@ -113,4 +113,5 @@ namespace PepperDash.Core;
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0);
}
}
}
}
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core;
namespace PepperDash.Core
{
/// <summary>
/// Bool change event args
/// </summary>
@@ -16,19 +16,19 @@ namespace PepperDash.Core;
/// </summary>
public bool State { get; set; }
/// <summary>
/// Boolean ushort value property
/// </summary>
/// <summary>
/// Gets or sets the IntValue
/// </summary>
public ushort IntValue { get { return (ushort)(State ? 1 : 0); } }
/// <summary>
/// Boolean change event args type
/// </summary>
/// <summary>
/// Gets or sets the Type
/// </summary>
public ushort Type { get; set; }
/// <summary>
/// Boolean change event args index
/// </summary>
/// <summary>
/// Gets or sets the Index
/// </summary>
public ushort Index { get; set; }
/// <summary>
@@ -64,9 +64,9 @@ namespace PepperDash.Core;
}
}
/// <summary>
/// Ushort change event args
/// </summary>
/// <summary>
/// Represents a UshrtChangeEventArgs
/// </summary>
public class UshrtChangeEventArgs : EventArgs
{
/// <summary>
@@ -74,14 +74,14 @@ namespace PepperDash.Core;
/// </summary>
public ushort IntValue { get; set; }
/// <summary>
/// Ushort change event args type
/// </summary>
/// <summary>
/// Gets or sets the Type
/// </summary>
public ushort Type { get; set; }
/// <summary>
/// Ushort change event args index
/// </summary>
/// <summary>
/// Gets or sets the Index
/// </summary>
public ushort Index { get; set; }
/// <summary>
@@ -117,9 +117,9 @@ namespace PepperDash.Core;
}
}
/// <summary>
/// String change event args
/// </summary>
/// <summary>
/// Represents a StringChangeEventArgs
/// </summary>
public class StringChangeEventArgs : EventArgs
{
/// <summary>
@@ -127,14 +127,14 @@ namespace PepperDash.Core;
/// </summary>
public string StringValue { get; set; }
/// <summary>
/// String change event args type
/// </summary>
/// <summary>
/// Gets or sets the Type
/// </summary>
public ushort Type { get; set; }
/// <summary>
/// string change event args index
/// </summary>
/// <summary>
/// Gets or sets the Index
/// </summary>
public ushort Index { get; set; }
/// <summary>
@@ -168,4 +168,5 @@ namespace PepperDash.Core;
Type = type;
Index = index;
}
}
}
}

View File

@@ -4,13 +4,13 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.GenericRESTfulCommunications;
namespace PepperDash.Core.GenericRESTfulCommunications
{
/// <summary>
/// Constants
/// </summary>
public class GenericRESTfulConstants
{
public class GenericRESTfulConstants
{
/// <summary>
/// Generic boolean change
/// </summary>
@@ -35,4 +35,5 @@ public class GenericRESTfulConstants
/// Error string change
/// </summary>
public const ushort ErrorStringChange = 203;
}
}

View File

@@ -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
{
/// <summary>
/// Generic RESTful communication class
/// </summary>
@@ -42,7 +42,7 @@ namespace PepperDash.Core.GenericRESTfulCommunications;
/// <param name="requestType"></param>
/// <param name="username"></param>
/// <param name="password"></param>
/// <param name="contentType"></param>
/// <param name="contentType"></param>
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;
/// <param name="url"></param>
/// <param name="port"></param>
/// <param name="requestType"></param>
/// <param name="contentType"></param>
/// <param name="contentType"></param>
/// <param name="username"></param>
/// <param name="password"></param>
private void SubmitRequestHttp(string url, ushort port, ushort requestType, string contentType, string username, string password)
@@ -123,7 +123,7 @@ namespace PepperDash.Core.GenericRESTfulCommunications;
/// <param name="url"></param>
/// <param name="port"></param>
/// <param name="requestType"></param>
/// <param name="contentType"></param>
/// <param name="contentType"></param>
/// <param name="username"></param>
/// <param name="password"></param>
private void SubmitRequestHttps(string url, ushort port, ushort requestType, string contentType, string username, string password)
@@ -252,4 +252,5 @@ namespace PepperDash.Core.GenericRESTfulCommunications;
StringChange(this, args);
}
}
}
}
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.JsonStandardObjects;
namespace PepperDash.Core.JsonStandardObjects
{
/// <summary>
/// Constants for simpl modules
/// </summary>
@@ -32,14 +32,14 @@ namespace PepperDash.Core.JsonStandardObjects;
/// </summary>
public DeviceConfig Device { get; set; }
/// <summary>
/// Device change event args type
/// </summary>
/// <summary>
/// Gets or sets the Type
/// </summary>
public ushort Type { get; set; }
/// <summary>
/// Device change event args index
/// </summary>
/// <summary>
/// Gets or sets the Index
/// </summary>
public ushort Index { get; set; }
/// <summary>
@@ -73,4 +73,5 @@ namespace PepperDash.Core.JsonStandardObjects;
Type = type;
Index = index;
}
}
}
}

View File

@@ -4,8 +4,8 @@ using Crestron.SimplSharp;
using PepperDash.Core.JsonToSimpl;
using Serilog.Events;
namespace PepperDash.Core.JsonStandardObjects;
namespace PepperDash.Core.JsonStandardObjects
{
/// <summary>
/// Device class
/// </summary>
@@ -58,6 +58,9 @@ namespace PepperDash.Core.JsonStandardObjects;
/// </summary>
/// <param name="uniqueID"></param>
/// <param name="deviceKey"></param>
/// <summary>
/// Initialize method
/// </summary>
public void Initialize(string uniqueID, string deviceKey)
{
// S+ set EvaluateFb low
@@ -179,4 +182,5 @@ namespace PepperDash.Core.JsonStandardObjects;
}
#endregion EventHandler Helpers
}
}
}

View File

@@ -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/#
@@ -47,60 +47,60 @@ namespace PepperDash.Core.JsonStandardObjects;
]
}
*/
/// <summary>
/// Device communication parameter class
/// </summary>
/// <summary>
/// Represents a ComParamsConfig
/// </summary>
public class ComParamsConfig
{
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the baudRate
/// </summary>
public int baudRate { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public int dataBits { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public int stopBits { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string parity { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string protocol { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string hardwareHandshake { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string softwareHandshake { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public int pacing { get; set; }
// convert properties for simpl
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the simplBaudRate
/// </summary>
public ushort simplBaudRate { get { return Convert.ToUInt16(baudRate); } }
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the simplDataBits
/// </summary>
public ushort simplDataBits { get { return Convert.ToUInt16(dataBits); } }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ushort simplStopBits { get { return Convert.ToUInt16(stopBits); } }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ushort simplPacing { get { return Convert.ToUInt16(pacing); } }
/// <summary>
@@ -117,43 +117,43 @@ namespace PepperDash.Core.JsonStandardObjects;
/// </summary>
public class TcpSshPropertiesConfig
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string address { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public int port { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string username { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string password { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public bool autoReconnect { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public int autoReconnectIntervalMs { get; set; }
// convert properties for simpl
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the simplPort
/// </summary>
public ushort simplPort { get { return Convert.ToUInt16(port); } }
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the simplAutoReconnect
/// </summary>
public ushort simplAutoReconnect { get { return (ushort)(autoReconnect ? 1 : 0); } }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ushort simplAutoReconnectIntervalMs { get { return Convert.ToUInt16(autoReconnectIntervalMs); } }
/// <summary>
@@ -170,31 +170,31 @@ namespace PepperDash.Core.JsonStandardObjects;
/// </summary>
public class ControlConfig
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string method { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string controlPortDevKey { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public int controlPortNumber { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ComParamsConfig comParams { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public TcpSshPropertiesConfig tcpSshProperties { get; set; }
// convert properties for simpl
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the simplControlPortNumber
/// </summary>
public ushort simplControlPortNumber { get { return Convert.ToUInt16(controlPortNumber); } }
/// <summary>
@@ -207,32 +207,32 @@ namespace PepperDash.Core.JsonStandardObjects;
}
}
/// <summary>
/// Device properties class
/// </summary>
/// <summary>
/// Represents a PropertiesConfig
/// </summary>
public class PropertiesConfig
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public int deviceId { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public bool enabled { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ControlConfig control { get; set; }
// convert properties for simpl
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the simplDeviceId
/// </summary>
public ushort simplDeviceId { get { return Convert.ToUInt16(deviceId); } }
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the simplEnabled
/// </summary>
public ushort simplEnabled { get { return (ushort)(enabled ? 1 : 0); } }
/// <summary>
@@ -249,8 +249,9 @@ namespace PepperDash.Core.JsonStandardObjects;
/// </summary>
public class RootObject
{
/// <summary>
/// The collection of devices
/// </summary>
/// <summary>
/// The collection of devices
/// </summary>
public List<DeviceConfig> devices { get; set; }
}
}
}

View File

@@ -4,78 +4,78 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.JsonToSimpl;
namespace PepperDash.Core.JsonToSimpl
{
/// <summary>
/// Constants for Simpl modules
/// </summary>
public class JsonToSimplConstants
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public const ushort BoolValueChange = 1;
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public const ushort JsonIsValidBoolChange = 2;
/// <summary>
/// Reports the if the device is 3-series compatible
/// </summary>
public const ushort ProgramCompatibility3SeriesChange = 3;
/// <summary>
/// Reports the if the device is 3-series compatible
/// </summary>
public const ushort ProgramCompatibility3SeriesChange = 3;
/// <summary>
/// Reports the if the device is 4-series compatible
/// </summary>
public const ushort ProgramCompatibility4SeriesChange = 4;
/// <summary>
/// Reports the if the device is 4-series compatible
/// </summary>
public const ushort ProgramCompatibility4SeriesChange = 4;
/// <summary>
/// Reports the device platform enum value
/// </summary>
public const ushort DevicePlatformValueChange = 5;
/// <summary>
/// Reports the device platform enum value
/// </summary>
public const ushort DevicePlatformValueChange = 5;
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public const ushort UshortValueChange = 101;
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public const ushort StringValueChange = 201;
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public const ushort FullPathToArrayChange = 202;
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public const ushort ActualFilePathChange = 203;
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public const ushort FilenameResolvedChange = 204;
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public const ushort FilePathResolvedChange = 205;
/// <summary>
/// Reports the root directory change
/// </summary>
public const ushort RootDirectoryChange = 206;
/// <summary>
/// Reports the root directory change
/// </summary>
public const ushort RootDirectoryChange = 206;
/// <summary>
/// Reports the room ID change
/// </summary>
public const ushort RoomIdChange = 207;
/// <summary>
/// Reports the room ID change
/// </summary>
public const ushort RoomIdChange = 207;
/// <summary>
/// Reports the room name change
/// </summary>
public const ushort RoomNameChange = 208;
/// <summary>
/// Reports the room name change
/// </summary>
public const ushort RoomNameChange = 208;
}
/// <summary>
@@ -88,33 +88,33 @@ namespace PepperDash.Core.JsonToSimpl;
/// </summary>
public class SPlusValueWrapper
{
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the ValueType
/// </summary>
public SPlusType ValueType { get; private set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ushort Index { get; private set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ushort BoolUShortValue { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string StringValue { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public SPlusValueWrapper() {}
/// <summary>
///
/// </summary>
/// <param name="type"></param>
/// <param name="index"></param>
/// <summary>
///
/// </summary>
/// <param name="type"></param>
/// <param name="index"></param>
public SPlusValueWrapper(SPlusType type, ushort index)
{
ValueType = type;
@@ -122,21 +122,22 @@ namespace PepperDash.Core.JsonToSimpl;
}
}
/// <summary>
/// S+ types enum
/// </summary>
/// <summary>
/// Enumeration of SPlusType values
/// </summary>
public enum SPlusType
{
/// <summary>
/// Digital
/// </summary>
/// <summary>
/// Digital
/// </summary>
Digital,
/// <summary>
/// Analog
/// </summary>
Analog,
/// <summary>
/// String
/// </summary>
String
}
/// <summary>
/// Analog
/// </summary>
Analog,
/// <summary>
/// String
/// </summary>
String
}
}

View File

@@ -7,11 +7,11 @@ using Serilog.Events;
//using PepperDash.Core;
namespace PepperDash.Core.JsonToSimpl;
/// <summary>
/// The global class to manage all the instances of JsonToSimplMaster
/// </summary>
namespace PepperDash.Core.JsonToSimpl
{
/// <summary>
/// The global class to manage all the instances of JsonToSimplMaster
/// </summary>
public class J2SGlobal
{
static List<JsonToSimplMaster> Masters = new List<JsonToSimplMaster>();
@@ -22,7 +22,10 @@ namespace PepperDash.Core.JsonToSimpl;
/// master, this will fail
/// </summary>
/// <param name="master">New master to add</param>
///
///
/// <summary>
/// AddMaster method
/// </summary>
public static void AddMaster(JsonToSimplMaster master)
{
if (master == null)
@@ -49,11 +52,12 @@ namespace PepperDash.Core.JsonToSimpl;
}
}
/// <summary>
/// Gets a master by its key. Case-insensitive
/// </summary>
/// <summary>
/// GetMasterByFile method
/// </summary>
public static JsonToSimplMaster GetMasterByFile(string file)
{
return Masters.FirstOrDefault(m => m.UniqueID.Equals(file, StringComparison.OrdinalIgnoreCase));
}
}
}
}

View File

@@ -3,20 +3,20 @@ using System.Linq;
using Newtonsoft.Json.Linq;
using Serilog.Events;
namespace PepperDash.Core.JsonToSimpl;
/// <summary>
/// Used to interact with an array of values with the S+ modules
/// </summary>
namespace PepperDash.Core.JsonToSimpl
{
/// <summary>
/// Represents a JsonToSimplArrayLookupChild
/// </summary>
public class JsonToSimplArrayLookupChild : JsonToSimplChildObjectBase
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string SearchPropertyName { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string SearchPropertyValue { get; set; }
int ArrayIndex;
@@ -76,9 +76,10 @@ namespace PepperDash.Core.JsonToSimpl;
PathSuffix == null ? "" : PathSuffix);
}
/// <summary>
/// Process all values
/// </summary>
/// <summary>
/// ProcessAll method
/// </summary>
/// <inheritdoc />
public override void ProcessAll()
{
if (FindInArray())
@@ -158,4 +159,5 @@ namespace PepperDash.Core.JsonToSimpl;
return false;
}
}
}
}

View File

@@ -3,39 +3,39 @@ using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
namespace PepperDash.Core.JsonToSimpl;
/// <summary>
/// Base class for JSON objects
/// </summary>
namespace PepperDash.Core.JsonToSimpl
{
/// <summary>
/// Base class for JSON objects
/// </summary>
public abstract class JsonToSimplChildObjectBase : IKeyed
{
/// <summary>
/// Notifies of bool change
/// </summary>
/// <summary>
/// Notifies of bool change
/// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary>
/// Notifies of ushort change
/// </summary>
/// <summary>
/// Notifies of ushort change
/// </summary>
public event EventHandler<UshrtChangeEventArgs> UShortChange;
/// <summary>
/// Notifies of string change
/// </summary>
/// <summary>
/// Notifies of string change
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// Delegate to get all values
/// </summary>
/// <summary>
/// Delegate to get all values
/// </summary>
public SPlusValuesDelegate GetAllValuesDelegate { get; set; }
/// <summary>
/// Use a callback to reduce task switch/threading
/// </summary>
/// <summary>
/// Gets or sets the SetAllPathsDelegate
/// </summary>
public SPlusValuesDelegate SetAllPathsDelegate { get; set; }
/// <summary>
/// Unique identifier for instance
/// </summary>
/// <summary>
/// Gets or sets the Key
/// </summary>
public string Key { get; protected set; }
/// <summary>
@@ -49,33 +49,33 @@ namespace PepperDash.Core.JsonToSimpl;
/// </summary>
public string PathSuffix { get; protected set; }
/// <summary>
/// Indicates if the instance is linked to an object
/// </summary>
/// <summary>
/// Gets or sets the LinkedToObject
/// </summary>
public bool LinkedToObject { get; protected set; }
/// <summary>
/// Reference to Master instance
/// </summary>
/// <summary>
/// Reference to Master instance
/// </summary>
protected JsonToSimplMaster Master;
/// <summary>
/// Paths to boolean values in JSON structure
/// </summary>
protected Dictionary<ushort, string> BoolPaths = new Dictionary<ushort, string>();
/// <summary>
/// Paths to numeric values in JSON structure
/// </summary>
/// <summary>
/// Paths to boolean values in JSON structure
/// </summary>
protected Dictionary<ushort, string> BoolPaths = new Dictionary<ushort, string>();
/// <summary>
/// Paths to numeric values in JSON structure
/// </summary>
protected Dictionary<ushort, string> UshortPaths = new Dictionary<ushort, string>();
/// <summary>
/// Paths to string values in JSON structure
/// </summary>
/// <summary>
/// Paths to string values in JSON structure
/// </summary>
protected Dictionary<ushort, string> StringPaths = new Dictionary<ushort, string>();
/// <summary>
/// Call this before doing anything else
/// </summary>
/// <param name="masterUniqueId"></param>
/// <param name="masterUniqueId"></param>
/// <param name="key"></param>
/// <param name="pathPrefix"></param>
/// <param name="pathSuffix"></param>
@@ -92,10 +92,13 @@ namespace PepperDash.Core.JsonToSimpl;
Debug.Console(1, "JSON Child [{0}] cannot link to master {1}", key, masterUniqueId);
}
/// <summary>
/// Sets the path prefix for the object
/// </summary>
/// <param name="pathPrefix"></param>
/// <summary>
/// Sets the path prefix for the object
/// </summary>
/// <param name="pathPrefix"></param>
/// <summary>
/// SetPathPrefix method
/// </summary>
public void SetPathPrefix(string pathPrefix)
{
PathPrefix = pathPrefix;
@@ -110,9 +113,9 @@ namespace PepperDash.Core.JsonToSimpl;
BoolPaths[index] = path;
}
/// <summary>
/// Set the JPath for a ushort out index.
/// </summary>
/// <summary>
/// SetUshortPath method
/// </summary>
public void SetUshortPath(ushort index, string path)
{
Debug.Console(1, "JSON Child[{0}] SetUshortPath {1}={2}", Key, index, path);
@@ -120,9 +123,9 @@ namespace PepperDash.Core.JsonToSimpl;
UshortPaths[index] = path;
}
/// <summary>
/// Set the JPath for a string output index.
/// </summary>
/// <summary>
/// SetStringPath method
/// </summary>
public void SetStringPath(ushort index, string path)
{
Debug.Console(1, "JSON Child[{0}] SetStringPath {1}={2}", Key, index, path);
@@ -130,10 +133,10 @@ namespace PepperDash.Core.JsonToSimpl;
StringPaths[index] = path;
}
/// <summary>
/// Evalutates all outputs with defined paths. called by S+ when paths are ready to process
/// and by Master when file is read.
/// </summary>
/// <summary>
/// ProcessAll method
/// </summary>
/// <inheritdoc />
public virtual void ProcessAll()
{
if (!LinkedToObject)
@@ -170,18 +173,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);
OnUShortChange(val, index, JsonToSimplConstants.UshortValueChange);
}
else { }
// OnUShortChange(0, 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)
@@ -272,54 +275,69 @@ namespace PepperDash.Core.JsonToSimpl;
GetAllValuesDelegate();
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="theValue"></param>
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="theValue"></param>
/// <summary>
/// USetBoolValue method
/// </summary>
public void USetBoolValue(ushort key, ushort theValue)
{
SetBoolValue(key, theValue == 1);
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="theValue"></param>
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="theValue"></param>
/// <summary>
/// SetBoolValue method
/// </summary>
public void SetBoolValue(ushort key, bool theValue)
{
if (BoolPaths.ContainsKey(key))
SetValueOnMaster(BoolPaths[key], new JValue(theValue));
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="theValue"></param>
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="theValue"></param>
/// <summary>
/// SetUShortValue method
/// </summary>
public void SetUShortValue(ushort key, ushort theValue)
{
if (UshortPaths.ContainsKey(key))
SetValueOnMaster(UshortPaths[key], new JValue(theValue));
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="theValue"></param>
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="theValue"></param>
/// <summary>
/// SetStringValue method
/// </summary>
public void SetStringValue(ushort key, string theValue)
{
if (StringPaths.ContainsKey(key))
SetValueOnMaster(StringPaths[key], new JValue(theValue));
}
/// <summary>
///
/// </summary>
/// <param name="keyPath"></param>
/// <param name="valueToSave"></param>
/// <summary>
///
/// </summary>
/// <param name="keyPath"></param>
/// <param name="valueToSave"></param>
/// <summary>
/// SetValueOnMaster method
/// </summary>
public void SetValueOnMaster(string keyPath, JValue valueToSave)
{
var path = GetFullPath(keyPath);
@@ -349,12 +367,12 @@ namespace PepperDash.Core.JsonToSimpl;
// Helpers for events
//******************************************************************************************
/// <summary>
/// Event helper
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
/// <summary>
/// Event helper
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnBoolChange(bool state, ushort index, ushort type)
{
var handler = BoolChange;
@@ -367,12 +385,12 @@ namespace PepperDash.Core.JsonToSimpl;
}
//******************************************************************************************
/// <summary>
/// Event helper
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
/// <summary>
/// Event helper
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnUShortChange(ushort state, ushort index, ushort type)
{
var handler = UShortChange;
@@ -384,12 +402,12 @@ namespace PepperDash.Core.JsonToSimpl;
}
}
/// <summary>
/// Event helper
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
/// <summary>
/// Event helper
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnStringChange(string value, ushort index, ushort type)
{
var handler = StringChange;
@@ -400,4 +418,5 @@ namespace PepperDash.Core.JsonToSimpl;
StringChange(this, args);
}
}
}
}
}

View File

@@ -7,280 +7,284 @@ using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json.Linq;
namespace PepperDash.Core.JsonToSimpl;
/// <summary>
/// Represents a JSON file that can be read and written to
/// </summary>
public class JsonToSimplFileMaster : JsonToSimplMaster
namespace PepperDash.Core.JsonToSimpl
{
/// <summary>
/// Sets the filepath as well as registers this with the Global.Masters list
/// Represents a JSON file that can be read and written to
/// </summary>
public string Filepath { get; private set; }
/// <summary>
/// Filepath to the actual file that will be read (Portal or local)
/// </summary>
public string ActualFilePath { get; private set; }
/// <summary>
///
/// </summary>
public string Filename { get; private set; }
/// <summary>
///
/// </summary>
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();
/*****************************************************************************************/
/// <summary>
/// SIMPL+ default constructor.
/// </summary>
public JsonToSimplFileMaster()
public class JsonToSimplFileMaster : JsonToSimplMaster
{
}
/// <summary>
/// Sets the filepath as well as registers this with the Global.Masters list
/// </summary>
public string Filepath { get; private set; }
/// <summary>
/// Read, evaluate and udpate status
/// </summary>
public void EvaluateFile(string filepath)
{
try
/// <summary>
/// Gets or sets the ActualFilePath
/// </summary>
public string ActualFilePath { get; private set; }
/// <summary>
/// Gets or sets the Filename
/// </summary>
public string Filename { get; private set; }
/// <summary>
///
/// </summary>
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();
/*****************************************************************************************/
/// <summary>
/// SIMPL+ default constructor.
/// </summary>
public JsonToSimplFileMaster()
{
OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange);
}
var dirSeparator = Path.DirectorySeparatorChar;
var dirSeparatorAlt = Path.AltDirectorySeparatorChar;
var series = CrestronEnvironment.ProgramCompatibility;
var is3Series = (eCrestronSeries.Series3 == (series & eCrestronSeries.Series3));
OnBoolChange(is3Series, 0,
JsonToSimplConstants.ProgramCompatibility3SeriesChange);
var is4Series = (eCrestronSeries.Series4 == (series & eCrestronSeries.Series4));
OnBoolChange(is4Series, 0,
JsonToSimplConstants.ProgramCompatibility4SeriesChange);
var isServer = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server;
OnBoolChange(isServer, 0,
JsonToSimplConstants.DevicePlatformValueChange);
// get the roomID
var roomId = Crestron.SimplSharp.InitialParametersClass.RoomId;
if (!string.IsNullOrEmpty(roomId))
/// <summary>
/// Read, evaluate and udpate status
/// </summary>
public void EvaluateFile(string filepath)
{
try
{
OnStringChange(roomId, 0, JsonToSimplConstants.RoomIdChange);
}
OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange);
// get the roomName
var roomName = Crestron.SimplSharp.InitialParametersClass.RoomName;
if (!string.IsNullOrEmpty(roomName))
{
OnStringChange(roomName, 0, JsonToSimplConstants.RoomNameChange);
}
var dirSeparator = Path.DirectorySeparatorChar;
var dirSeparatorAlt = Path.AltDirectorySeparatorChar;
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);
var series = CrestronEnvironment.ProgramCompatibility;
var is3Series = (eCrestronSeries.Series3 == (series & eCrestronSeries.Series3));
OnBoolChange(is3Series, 0,
JsonToSimplConstants.ProgramCompatibility3SeriesChange);
var is4Series = (eCrestronSeries.Series4 == (series & eCrestronSeries.Series4));
OnBoolChange(is4Series, 0,
JsonToSimplConstants.ProgramCompatibility4SeriesChange);
var isServer = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server;
OnBoolChange(isServer, 0,
JsonToSimplConstants.DevicePlatformValueChange);
// get the roomID
var roomId = Crestron.SimplSharp.InitialParametersClass.RoomId;
if (!string.IsNullOrEmpty(roomId))
{
OnStringChange(roomId, 0, JsonToSimplConstants.RoomIdChange);
}
// get the roomName
var roomName = Crestron.SimplSharp.InitialParametersClass.RoomName;
if (!string.IsNullOrEmpty(roomName))
{
OnStringChange(roomName, 0, JsonToSimplConstants.RoomNameChange);
}
var rootDirectory = Directory.GetApplicationRootDirectory();
OnStringChange(rootDirectory, 0, JsonToSimplConstants.RootDirectoryChange);
var splusPath = string.Empty;
if (Regex.IsMatch(filepath, @"user", RegexOptions.IgnoreCase))
{
if (is4Series)
splusPath = Regex.Replace(filepath, "user", "user", RegexOptions.IgnoreCase);
else if (isServer)
splusPath = Regex.Replace(filepath, "user", "User", RegexOptions.IgnoreCase);
else
splusPath = filepath;
}
filepath = splusPath.Replace(dirSeparatorAlt, dirSeparator);
Filepath = string.Format("{1}{0}{2}", dirSeparator, rootDirectory,
filepath.TrimStart(dirSeparator, dirSeparatorAlt));
OnStringChange(string.Format("Attempting to evaluate {0}", Filepath), 0, JsonToSimplConstants.StringValueChange);
if (string.IsNullOrEmpty(Filepath))
{
OnStringChange(string.Format("Cannot evaluate file. JSON file path not set"), 0, JsonToSimplConstants.StringValueChange);
CrestronConsole.PrintLine("Cannot evaluate file. JSON file path not set");
return;
}
// get file directory and name to search
var fileDirectory = Path.GetDirectoryName(Filepath);
var fileName = Path.GetFileName(Filepath);
OnStringChange(string.Format("Checking '{0}' for '{1}'", fileDirectory, fileName), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "Checking '{0}' for '{1}'", fileDirectory, fileName);
if (Directory.Exists(fileDirectory))
{
// get the directory info
var directoryInfo = new DirectoryInfo(fileDirectory);
// get the file to be read
var actualFile = directoryInfo.GetFiles(fileName).FirstOrDefault();
if (actualFile == null)
{
var msg = string.Format("JSON file not found: {0}", Filepath);
OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange);
CrestronConsole.PrintLine(msg);
ErrorLog.Error(msg);
return;
}
// \xSE\xR\PDT000-Template_Main_Config-Combined_DSP_v00.02.json
// \USER\PDT000-Template_Main_Config-Combined_DSP_v00.02.json
ActualFilePath = actualFile.FullName;
OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange);
OnStringChange(string.Format("Actual JSON file is {0}", ActualFilePath), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "Actual JSON file is {0}", ActualFilePath);
Filename = actualFile.Name;
OnStringChange(Filename, 0, JsonToSimplConstants.FilenameResolvedChange);
OnStringChange(string.Format("JSON Filename is {0}", Filename), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "JSON Filename is {0}", Filename);
FilePathName = string.Format(@"{0}{1}", actualFile.DirectoryName, dirSeparator);
OnStringChange(string.Format(@"{0}", actualFile.DirectoryName), 0, JsonToSimplConstants.FilePathResolvedChange);
OnStringChange(string.Format(@"JSON File Path is {0}", actualFile.DirectoryName), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "JSON File Path is {0}", FilePathName);
var json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII);
JsonObject = JObject.Parse(json);
foreach (var child in Children)
child.ProcessAll();
OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange);
}
else
splusPath = filepath;
{
OnStringChange(string.Format("'{0}' not found", fileDirectory), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "'{0}' not found", fileDirectory);
}
}
catch (Exception e)
{
var msg = string.Format("EvaluateFile Exception: Message\r{0}", e.Message);
OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange);
CrestronConsole.PrintLine(msg);
ErrorLog.Error(msg);
var stackTrace = string.Format("EvaluateFile: Stack Trace\r{0}", e.StackTrace);
OnStringChange(stackTrace, 0, JsonToSimplConstants.StringValueChange);
CrestronConsole.PrintLine(stackTrace);
ErrorLog.Error(stackTrace);
}
}
/// <summary>
/// Sets the debug level
/// </summary>
/// <param name="level"></param>
/// <summary>
/// setDebugLevel method
/// </summary>
public void setDebugLevel(uint level)
{
Debug.SetDebugLevel(level);
}
/// <summary>
/// Saves the values to the file
/// </summary>
public override void Save()
{
// this code is duplicated in the other masters!!!!!!!!!!!!!
UnsavedValues = new Dictionary<string, JValue>();
// 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();
}
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))
if (UnsavedValues == null || UnsavedValues.Count == 0)
{
OnStringChange(string.Format("Cannot evaluate file. JSON file path not set"), 0, JsonToSimplConstants.StringValueChange);
CrestronConsole.PrintLine("Cannot evaluate file. JSON file path not set");
Debug.Console(1, "Master [{0}] No updated values to save. Skipping", UniqueID);
return;
}
// get file directory and name to search
var fileDirectory = Path.GetDirectoryName(Filepath);
var fileName = Path.GetFileName(Filepath);
OnStringChange(string.Format("Checking '{0}' for '{1}'", fileDirectory, fileName), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "Checking '{0}' for '{1}'", fileDirectory, fileName);
if (Directory.Exists(fileDirectory))
lock (FileLock)
{
// get the directory info
var directoryInfo = new DirectoryInfo(fileDirectory);
// get the file to be read
var actualFile = directoryInfo.GetFiles(fileName).FirstOrDefault();
if (actualFile == null)
Debug.Console(1, "Saving");
foreach (var path in UnsavedValues.Keys)
{
var msg = string.Format("JSON file not found: {0}", Filepath);
OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange);
CrestronConsole.PrintLine(msg);
ErrorLog.Error(msg);
return;
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]);
}
}
// \xSE\xR\PDT000-Template_Main_Config-Combined_DSP_v00.02.json
// \USER\PDT000-Template_Main_Config-Combined_DSP_v00.02.json
ActualFilePath = actualFile.FullName;
OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange);
OnStringChange(string.Format("Actual JSON file is {0}", ActualFilePath), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "Actual JSON file is {0}", ActualFilePath);
Filename = actualFile.Name;
OnStringChange(Filename, 0, JsonToSimplConstants.FilenameResolvedChange);
OnStringChange(string.Format("JSON Filename is {0}", Filename), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "JSON Filename is {0}", Filename);
FilePathName = string.Format(@"{0}{1}", actualFile.DirectoryName, dirSeparator);
OnStringChange(string.Format(@"{0}", actualFile.DirectoryName), 0, JsonToSimplConstants.FilePathResolvedChange);
OnStringChange(string.Format(@"JSON File Path is {0}", actualFile.DirectoryName), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "JSON File Path is {0}", FilePathName);
var json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII);
JsonObject = JObject.Parse(json);
foreach (var child in Children)
child.ProcessAll();
OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange);
}
else
{
OnStringChange(string.Format("'{0}' not found", fileDirectory), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "'{0}' not found", fileDirectory);
}
}
catch (Exception e)
{
var msg = string.Format("EvaluateFile Exception: Message\r{0}", e.Message);
OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange);
CrestronConsole.PrintLine(msg);
ErrorLog.Error(msg);
var stackTrace = string.Format("EvaluateFile: Stack Trace\r{0}", e.StackTrace);
OnStringChange(stackTrace, 0, JsonToSimplConstants.StringValueChange);
CrestronConsole.PrintLine(stackTrace);
ErrorLog.Error(stackTrace);
}
}
/// <summary>
/// Sets the debug level
/// </summary>
/// <param name="level"></param>
public void setDebugLevel(uint level)
{
Debug.SetDebugLevel(level);
}
/// <summary>
/// Saves the values to the file
/// </summary>
public override void Save()
{
// this code is duplicated in the other masters!!!!!!!!!!!!!
UnsavedValues = new Dictionary<string, JValue>();
// Make each child update their values into master object
foreach (var child in Children)
{
Debug.Console(1, "Master [{0}] checking child [{1}] for updates to save", UniqueID, child.Key);
child.UpdateInputsForMaster();
}
if (UnsavedValues == null || UnsavedValues.Count == 0)
{
Debug.Console(1, "Master [{0}] No updated values to save. Skipping", UniqueID);
return;
}
lock (FileLock)
{
Debug.Console(1, "Saving");
foreach (var path in UnsavedValues.Keys)
{
var tokenToReplace = JsonObject.SelectToken(path);
if (tokenToReplace != null)
{// It's found
tokenToReplace.Replace(UnsavedValues[path]);
Debug.Console(1, "JSON Master[{0}] Updating '{1}'", UniqueID, path);
}
else // No token. Let's make one
using (StreamWriter sw = new StreamWriter(ActualFilePath))
{
//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;
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;
}
}
}
}

View File

@@ -1,17 +1,18 @@
namespace PepperDash.Core.JsonToSimpl;
/// <summary>
///
/// </summary>
namespace PepperDash.Core.JsonToSimpl
{
/// <summary>
/// Represents a JsonToSimplFixedPathObject
/// </summary>
public class JsonToSimplFixedPathObject : JsonToSimplChildObjectBase
{
/// <summary>
/// Constructor
/// </summary>
/// <summary>
/// Constructor
/// </summary>
public JsonToSimplFixedPathObject()
{
this.LinkedToObject = true;
}
}
}
}

View File

@@ -3,35 +3,35 @@ using System.Collections.Generic;
using Crestron.SimplSharp;
using Newtonsoft.Json.Linq;
namespace PepperDash.Core.JsonToSimpl;
/// <summary>
/// Generic Master
/// </summary>
public class JsonToSimplGenericMaster : JsonToSimplMaster
namespace PepperDash.Core.JsonToSimpl
{
/// <summary>
/// Represents a JsonToSimplGenericMaster
/// </summary>
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();
/// <summary>
/// Callback action for saving
/// </summary>
/// <summary>
/// Gets or sets the SaveCallback
/// </summary>
public Action<string> SaveCallback { get; set; }
/*****************************************************************************************/
/// <summary>
/// SIMPL+ default constructor.
/// </summary>
/// SIMPL+ default constructor.
/// </summary>
public JsonToSimplGenericMaster()
{
{
}
/// <summary>
@@ -60,6 +60,9 @@ namespace PepperDash.Core.JsonToSimpl;
/// Loads JSON into JsonObject, but does not trigger evaluation by children
/// </summary>
/// <param name="json"></param>
/// <summary>
/// SetJsonWithoutEvaluating method
/// </summary>
public void SetJsonWithoutEvaluating(string json)
{
try
@@ -72,13 +75,14 @@ namespace PepperDash.Core.JsonToSimpl;
}
}
/// <summary>
///
/// </summary>
/// <summary>
/// Save method
/// </summary>
/// <inheritdoc />
public override void Save()
{
// this code is duplicated in the other masters!!!!!!!!!!!!!
UnsavedValues = new Dictionary<string, JValue>();
UnsavedValues = new Dictionary<string, JValue>();
// Make each child update their values into master object
foreach (var child in Children)
{
@@ -114,4 +118,5 @@ namespace PepperDash.Core.JsonToSimpl;
else
Debug.Console(0, this, "WARNING: No save callback defined.");
}
}
}
}

View File

@@ -2,32 +2,33 @@ using System;
using System.Collections.Generic;
using System.IO;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace PepperDash.Core.JsonToSimpl;
/// <summary>
/// Abstract base class for JsonToSimpl interactions
/// </summary>
namespace PepperDash.Core.JsonToSimpl
{
/// <summary>
/// Abstract base class for JsonToSimpl interactions
/// </summary>
public abstract class JsonToSimplMaster : IKeyed
{
/// <summary>
/// Notifies of bool change
/// </summary>
/// <summary>
/// Notifies of bool change
/// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary>
/// Notifies of ushort change
/// </summary>
/// <summary>
/// Notifies of ushort change
/// </summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// <summary>
/// Notifies of string change
/// </summary>
/// <summary>
/// Notifies of string change
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// A collection of associated child modules
/// </summary>
/// <summary>
/// A collection of associated child modules
/// </summary>
protected List<JsonToSimplChildObjectBase> Children = new List<JsonToSimplChildObjectBase>();
/*****************************************************************************************/
@@ -37,9 +38,9 @@ namespace PepperDash.Core.JsonToSimpl;
/// </summary>
public string Key { get { return UniqueID; } }
/// <summary>
/// A unique ID
/// </summary>
/// <summary>
/// Gets or sets the UniqueID
/// </summary>
public string UniqueID { get; protected set; }
/// <summary>
@@ -52,10 +53,9 @@ namespace PepperDash.Core.JsonToSimpl;
}
string _DebugName = "";
/// <summary>
/// This will be prepended to all paths to allow path swapping or for more organized
/// sub-paths
/// </summary>
/// <summary>
/// Gets or sets the PathPrefix
/// </summary>
public string PathPrefix { get; set; }
/// <summary>
@@ -82,9 +82,9 @@ namespace PepperDash.Core.JsonToSimpl;
}
}
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the JsonObject
/// </summary>
public JObject JsonObject { get; protected set; }
/*****************************************************************************************/
@@ -119,6 +119,9 @@ namespace PepperDash.Core.JsonToSimpl;
/// Adds a child "module" to this master
/// </summary>
/// <param name="child"></param>
/// <summary>
/// AddChild method
/// </summary>
public void AddChild(JsonToSimplChildObjectBase child)
{
if (!Children.Contains(child))
@@ -127,9 +130,9 @@ namespace PepperDash.Core.JsonToSimpl;
}
}
/// <summary>
/// Called from the child to add changed or new values for saving
/// </summary>
/// <summary>
/// AddUnsavedValue method
/// </summary>
public void AddUnsavedValue(string path, JValue value)
{
if (UnsavedValues.ContainsKey(path))
@@ -141,9 +144,9 @@ namespace PepperDash.Core.JsonToSimpl;
//Debug.Console(0, "Master[{0}] Unsaved size={1}", UniqueID, UnsavedValues.Count);
}
/// <summary>
/// Saves the file
/// </summary>
/// <summary>
/// Saves the file
/// </summary>
public abstract void Save();
@@ -152,14 +155,18 @@ namespace PepperDash.Core.JsonToSimpl;
/// </summary>
public static class JsonFixes
{
/// <summary>
/// Deserializes a string into a JObject
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
/// <summary>
/// Deserializes a string into a JObject
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
public static JObject ParseObject(string json)
{
using (var reader = new JsonTextReader(new StringReader(json)))
#if NET6_0
using (var reader = new JsonTextReader(new System.IO.StringReader(json)))
#else
using (var reader = new JsonTextReader(new Crestron.SimplSharp.CrestronIO.StringReader(json)))
#endif
{
var startDepth = reader.Depth;
var obj = JObject.Load(reader);
@@ -169,15 +176,21 @@ namespace PepperDash.Core.JsonToSimpl;
}
}
/// <summary>
/// Deserializes a string into a JArray
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
/// <summary>
/// Deserializes a string into a JArray
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
/// <summary>
/// ParseArray method
/// </summary>
public static JArray ParseArray(string json)
{
using (var reader = new JsonTextReader(new StringReader(json)))
#if NET6_0
using (var reader = new JsonTextReader(new System.IO.StringReader(json)))
#else
using (var reader = new JsonTextReader(new Crestron.SimplSharp.CrestronIO.StringReader(json)))
#endif
{
var startDepth = reader.Depth;
var obj = JArray.Load(reader);
@@ -220,12 +233,12 @@ namespace PepperDash.Core.JsonToSimpl;
}
}
/// <summary>
/// Helper event
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
/// <summary>
/// Helper event
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnStringChange(string value, ushort index, ushort type)
{
if (StringChange != null)
@@ -236,3 +249,4 @@ namespace PepperDash.Core.JsonToSimpl;
}
}
}
}

View File

@@ -6,22 +6,22 @@ using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json.Linq;
using PepperDash.Core.Config;
namespace PepperDash.Core.JsonToSimpl;
/// <summary>
/// Portal File Master
/// </summary>
public class JsonToSimplPortalFileMaster : JsonToSimplMaster
namespace PepperDash.Core.JsonToSimpl
{
/// <summary>
/// Portal File Master
/// </summary>
public class JsonToSimplPortalFileMaster : JsonToSimplMaster
{
/// <summary>
/// Sets the filepath as well as registers this with the Global.Masters list
/// </summary>
public string PortalFilepath { get; private set; }
/// <summary>
/// File path of the actual file being read (Portal or local)
/// </summary>
public string ActualFilePath { get; private set; }
/// <summary>
/// Gets or sets the ActualFilePath
/// </summary>
public string ActualFilePath { get; private set; }
/*****************************************************************************************/
/** Privates **/
@@ -33,10 +33,10 @@ public class JsonToSimplPortalFileMaster : JsonToSimplMaster
/*****************************************************************************************/
/// <summary>
/// SIMPL+ default constructor.
/// </summary>
/// SIMPL+ default constructor.
/// </summary>
public JsonToSimplPortalFileMaster()
{
{
}
/// <summary>
@@ -64,7 +64,7 @@ public class JsonToSimplPortalFileMaster : JsonToSimplMaster
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.
@@ -78,7 +78,7 @@ public class JsonToSimplPortalFileMaster : JsonToSimplMaster
// 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
{
@@ -128,6 +128,9 @@ public class JsonToSimplPortalFileMaster : JsonToSimplMaster
///
/// </summary>
/// <param name="level"></param>
/// <summary>
/// setDebugLevel method
/// </summary>
public void setDebugLevel(uint level)
{
Debug.SetDebugLevel(level);
@@ -188,3 +191,4 @@ public class JsonToSimplPortalFileMaster : JsonToSimplMaster
}
}
}
}

View File

@@ -7,30 +7,37 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PepperDash.Core.Logging;
public class CrestronEnricher : ILogEventEnricher
namespace PepperDash.Core.Logging
{
static readonly string _appName;
static CrestronEnricher()
/// <summary>
/// Represents a CrestronEnricher
/// </summary>
public class CrestronEnricher : ILogEventEnricher
{
switch (CrestronEnvironment.DevicePlatform)
static readonly string _appName;
static CrestronEnricher()
{
case eDevicePlatform.Appliance:
_appName = $"App {InitialParametersClass.ApplicationNumber}";
break;
case eDevicePlatform.Server:
_appName = $"{InitialParametersClass.RoomId}";
break;
switch (CrestronEnvironment.DevicePlatform)
{
case eDevicePlatform.Appliance:
_appName = $"App {InitialParametersClass.ApplicationNumber}";
break;
case eDevicePlatform.Server:
_appName = $"{InitialParametersClass.RoomId}";
break;
}
}
/// <summary>
/// Enrich method
/// </summary>
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
var property = propertyFactory.CreateProperty("App", _appName);
logEvent.AddOrUpdateProperty(property);
}
}
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
var property = propertyFactory.CreateProperty("App", _appName);
logEvent.AddOrUpdateProperty(property);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -9,45 +9,56 @@ using System.IO;
using System.Text;
namespace PepperDash.Core;
public class DebugConsoleSink : ILogEventSink
namespace PepperDash.Core
{
private readonly ITextFormatter _textFormatter;
public void Emit(LogEvent logEvent)
/// <summary>
/// Represents a DebugConsoleSink
/// </summary>
public class DebugConsoleSink : ILogEventSink
{
if (!Debug.IsRunningOnAppliance) return;
private readonly ITextFormatter _textFormatter;
/*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)
/// <summary>
/// Emit method
/// </summary>
public void Emit(LogEvent logEvent)
{
message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue,3}]: {logEvent.RenderMessage()}";
}*/
if (!Debug.IsRunningOnAppliance) return;
var buffer = new StringWriter(new StringBuilder(256));
/*string message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}]{logEvent.RenderMessage()}";
_textFormatter.Format(logEvent, buffer);
if(logEvent.Properties.TryGetValue("Key",out var value) && value is ScalarValue sv && sv.Value is string rawValue)
{
message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue,3}]: {logEvent.RenderMessage()}";
}*/
var message = buffer.ToString();
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();
}
CrestronConsole.PrintLine(message);
}
public DebugConsoleSink(ITextFormatter formatProvider )
public static class DebugConsoleSinkExtensions
{
_textFormatter = formatProvider ?? new JsonFormatter();
/// <summary>
/// DebugConsoleSink method
/// </summary>
public static LoggerConfiguration DebugConsoleSink(
this LoggerSinkConfiguration loggerConfiguration,
ITextFormatter formatProvider = null)
{
return loggerConfiguration.Sink(new DebugConsoleSink(formatProvider));
}
}
}
public static class DebugConsoleSinkExtensions
{
public static LoggerConfiguration DebugConsoleSink(
this LoggerSinkConfiguration loggerConfiguration,
ITextFormatter formatProvider = null)
{
return loggerConfiguration.Sink(new DebugConsoleSink(formatProvider));
}
}

View File

@@ -6,275 +6,288 @@ using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json;
namespace PepperDash.Core;
/// <summary>
/// Represents a debugging context
/// </summary>
public class DebugContext
namespace PepperDash.Core
{
/// <summary>
/// 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.
/// Represents a debugging context
/// </summary>
public string Key { get; private set; }
///// <summary>
///// The name of the file containing the current debug settings.
///// </summary>
//string FileName = string.Format(@"\nvram\debug\app{0}Debug.json", InitialParametersClass.ApplicationNumber);
DebugContextSaveData SaveData;
int SaveTimeoutMs = 30000;
CTimer SaveTimer;
static List<DebugContext> Contexts = new List<DebugContext>();
/// <summary>
/// Creates or gets a debug context
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static DebugContext GetDebugContext(string key)
public class DebugContext
{
var context = Contexts.FirstOrDefault(c => c.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
if (context == null)
/// <summary>
/// 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.
/// </summary>
public string Key { get; private set; }
/// <summary>
/// The name of the file containing the current debug settings.
/// </summary>
//string FileName = string.Format(@"\nvram\debug\app{0}Debug.json", InitialParametersClass.ApplicationNumber);
DebugContextSaveData SaveData;
int SaveTimeoutMs = 30000;
CTimer SaveTimer;
static List<DebugContext> Contexts = new List<DebugContext>();
/// <summary>
/// Creates or gets a debug context
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
/// <summary>
/// GetDebugContext method
/// </summary>
public static DebugContext GetDebugContext(string key)
{
context = new DebugContext(key);
Contexts.Add(context);
}
return context;
}
/// <summary>
/// Do not use. For S+ access.
/// </summary>
public DebugContext() { }
DebugContext(string key)
{
Key = key;
if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SimplSharpPro)
{
// Add command to console
CrestronConsole.AddNewConsoleCommand(SetDebugFromConsole, "appdebug",
"appdebug:P [0-2]: Sets the application's console debug message level",
ConsoleAccessLevelEnum.AccessOperator);
}
CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler;
LoadMemory();
}
/// <summary>
/// Used to save memory when shutting down
/// </summary>
/// <param name="programEventType"></param>
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
if (programEventType == eProgramStatusEventType.Stopping)
{
if (SaveTimer != null)
var context = Contexts.FirstOrDefault(c => c.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
if (context == null)
{
SaveTimer.Stop();
SaveTimer = null;
context = new DebugContext(key);
Contexts.Add(context);
}
Console(0, "Saving debug settings");
SaveMemory();
return context;
}
}
/// <summary>
/// Callback for console command
/// </summary>
/// <param name="levelString"></param>
public void SetDebugFromConsole(string levelString)
{
try
/// <summary>
/// Do not use. For S+ access.
/// </summary>
public DebugContext() { }
DebugContext(string key)
{
if (string.IsNullOrEmpty(levelString.Trim()))
Key = key;
if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SimplSharpPro)
{
CrestronConsole.ConsoleCommandResponse("AppDebug level = {0}", SaveData.Level);
return;
// Add command to console
CrestronConsole.AddNewConsoleCommand(SetDebugFromConsole, "appdebug",
"appdebug:P [0-2]: Sets the application's console debug message level",
ConsoleAccessLevelEnum.AccessOperator);
}
SetDebugLevel(Convert.ToInt32(levelString));
CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler;
LoadMemory();
}
catch
/// <summary>
/// Used to save memory when shutting down
/// </summary>
/// <param name="programEventType"></param>
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
CrestronConsole.PrintLine("Usage: appdebug:P [0-2]");
}
}
/// <summary>
/// Sets the debug level
/// </summary>
/// <param name="level"> Valid values 0 (no debug), 1 (critical), 2 (all messages)</param>
public void SetDebugLevel(int level)
{
if (level <= 2)
{
SaveData.Level = level;
SaveMemoryOnTimeout();
CrestronConsole.PrintLine("[Application {0}], Debug level set to {1}",
InitialParametersClass.ApplicationNumber, SaveData.Level);
}
}
/// <summary>
/// Prints message to console if current debug level is equal to or higher than the level of this message.
/// Uses CrestronConsole.PrintLine.
/// </summary>
/// <param name="level"></param>
/// <param name="format">Console format string</param>
/// <param name="items">Object parameters</param>
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));
}
/// <summary>
/// Appends a device Key to the beginning of a message
/// </summary>
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));
}
/// <summary>
///
/// </summary>
/// <param name="level"></param>
/// <param name="dev"></param>
/// <param name="errorLogLevel"></param>
/// <param name="format"></param>
/// <param name="items"></param>
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);
}
}
/// <summary>
///
/// </summary>
/// <param name="level"></param>
/// <param name="errorLogLevel"></param>
/// <param name="format"></param>
/// <param name="items"></param>
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);
}
}
/// <summary>
///
/// </summary>
/// <param name="errorLogLevel"></param>
/// <param name="str"></param>
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;
}
}
/// <summary>
/// Writes the memory object after timeout
/// </summary>
void SaveMemoryOnTimeout()
{
if (SaveTimer == null)
SaveTimer = new CTimer(o =>
if (programEventType == eProgramStatusEventType.Stopping)
{
SaveTimer = null;
SaveMemory();
}, SaveTimeoutMs);
else
SaveTimer.Reset(SaveTimeoutMs);
}
/// <summary>
/// Writes the memory - use SaveMemoryOnTimeout
/// </summary>
void SaveMemory()
{
using (StreamWriter sw = new StreamWriter(GetMemoryFileName()))
{
var json = JsonConvert.SerializeObject(SaveData);
sw.Write(json);
sw.Flush();
}
}
/// <summary>
///
/// </summary>
void LoadMemory()
{
var file = GetMemoryFileName();
if (File.Exists(file))
{
using (StreamReader sr = new StreamReader(file))
{
var data = JsonConvert.DeserializeObject<DebugContextSaveData>(sr.ReadToEnd());
if (data != null)
if (SaveTimer != null)
{
SaveData = data;
Debug.Console(1, "Debug memory restored from file");
SaveTimer.Stop();
SaveTimer = null;
}
Console(0, "Saving debug settings");
SaveMemory();
}
}
/// <summary>
/// Callback for console command
/// </summary>
/// <param name="levelString"></param>
/// <summary>
/// SetDebugFromConsole method
/// </summary>
public void SetDebugFromConsole(string levelString)
{
try
{
if (string.IsNullOrEmpty(levelString.Trim()))
{
CrestronConsole.ConsoleCommandResponse("AppDebug level = {0}", SaveData.Level);
return;
}
else
SaveData = new DebugContextSaveData();
SetDebugLevel(Convert.ToInt32(levelString));
}
catch
{
CrestronConsole.PrintLine("Usage: appdebug:P [0-2]");
}
}
/// <summary>
/// Sets the debug level
/// </summary>
/// <param name="level"> Valid values 0 (no debug), 1 (critical), 2 (all messages)</param>
/// <summary>
/// SetDebugLevel method
/// </summary>
public void SetDebugLevel(int level)
{
if (level <= 2)
{
SaveData.Level = level;
SaveMemoryOnTimeout();
CrestronConsole.PrintLine("[Application {0}], Debug level set to {1}",
InitialParametersClass.ApplicationNumber, SaveData.Level);
}
}
/// <summary>
/// Prints message to console if current debug level is equal to or higher than the level of this message.
/// Uses CrestronConsole.PrintLine.
/// </summary>
/// <param name="level"></param>
/// <param name="format">Console format string</param>
/// <param name="items">Object parameters</param>
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));
}
/// <summary>
/// Console method
/// </summary>
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));
}
/// <summary>
///
/// </summary>
/// <param name="level"></param>
/// <param name="dev"></param>
/// <param name="errorLogLevel"></param>
/// <param name="format"></param>
/// <param name="items"></param>
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);
}
}
/// <summary>
///
/// </summary>
/// <param name="level"></param>
/// <param name="errorLogLevel"></param>
/// <param name="format"></param>
/// <param name="items"></param>
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);
}
}
/// <summary>
///
/// </summary>
/// <param name="errorLogLevel"></param>
/// <param name="str"></param>
/// <summary>
/// LogError method
/// </summary>
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;
}
}
/// <summary>
/// Writes the memory object after timeout
/// </summary>
void SaveMemoryOnTimeout()
{
if (SaveTimer == null)
SaveTimer = new CTimer(o =>
{
SaveTimer = null;
SaveMemory();
}, SaveTimeoutMs);
else
SaveTimer.Reset(SaveTimeoutMs);
}
/// <summary>
/// Writes the memory - use SaveMemoryOnTimeout
/// </summary>
void SaveMemory()
{
using (StreamWriter sw = new StreamWriter(GetMemoryFileName()))
{
var json = JsonConvert.SerializeObject(SaveData);
sw.Write(json);
sw.Flush();
}
}
/// <summary>
///
/// </summary>
void LoadMemory()
{
var file = GetMemoryFileName();
if (File.Exists(file))
{
using (StreamReader sr = new StreamReader(file))
{
var data = JsonConvert.DeserializeObject<DebugContextSaveData>(sr.ReadToEnd());
if (data != null)
{
SaveData = data;
Debug.Console(1, "Debug memory restored from file");
return;
}
else
SaveData = new DebugContextSaveData();
}
}
}
/// <summary>
/// Helper to get the file path for this app's debug memory
/// </summary>
string GetMemoryFileName()
{
return string.Format(@"\NVRAM\debugSettings\program{0}-{1}", InitialParametersClass.ApplicationNumber, Key);
}
}
/// <summary>
/// Helper to get the file path for this app's debug memory
/// </summary>
string GetMemoryFileName()
{
return string.Format(@"\NVRAM\debugSettings\program{0}-{1}", InitialParametersClass.ApplicationNumber, Key);
}
}
/// <summary>
///
/// </summary>
public class DebugContextSaveData
{
/// <summary>
///
/// </summary>
public int Level { get; set; }
public class DebugContextSaveData
{
/// <summary>
///
/// </summary>
public int Level { get; set; }
}
}

View File

@@ -3,26 +3,33 @@ using Crestron.SimplSharp.CrestronLogger;
using Serilog.Core;
using Serilog.Events;
namespace PepperDash.Core.Logging;
public class DebugCrestronLoggerSink : ILogEventSink
namespace PepperDash.Core.Logging
{
public void Emit(LogEvent logEvent)
/// <summary>
/// Represents a DebugCrestronLoggerSink
/// </summary>
public class DebugCrestronLoggerSink : ILogEventSink
{
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)
/// <summary>
/// Emit method
/// </summary>
public void Emit(LogEvent logEvent)
{
message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue}]: {logEvent.RenderMessage()}";
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);
}
CrestronLogger.WriteToLog(message, (uint)logEvent.Level);
}
public DebugCrestronLoggerSink()
{
CrestronLogger.Initialize(1, LoggerModeEnum.RM);
public DebugCrestronLoggerSink()
{
CrestronLogger.Initialize(1, LoggerModeEnum.RM);
}
}
}

View File

@@ -9,56 +9,63 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PepperDash.Core.Logging;
public class DebugErrorLogSink : ILogEventSink
namespace PepperDash.Core.Logging
{
private ITextFormatter _formatter;
private Dictionary<LogEventLevel, Action<string>> _errorLogMap = new Dictionary<LogEventLevel, Action<string>>
/// <summary>
/// Represents a DebugErrorLogSink
/// </summary>
public class DebugErrorLogSink : ILogEventSink
{
{ 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 ITextFormatter _formatter;
if (_formatter == null)
private Dictionary<LogEventLevel, Action<string>> _errorLogMap = new Dictionary<LogEventLevel, Action<string>>
{
var programId = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance
? $"App {InitialParametersClass.ApplicationNumber}"
: $"Room {InitialParametersClass.RoomId}";
{ 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) }
};
/// <summary>
/// Emit method
/// </summary>
public void Emit(LogEvent logEvent)
{
string message;
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)
if (_formatter == null)
{
message = $"[{logEvent.Timestamp}][{logEvent.Level}][{programId}][{rawValue}]: {logEvent.RenderMessage()}";
var programId = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance
? $"App {InitialParametersClass.ApplicationNumber}"
: $"Room {InitialParametersClass.RoomId}";
message = $"[{logEvent.Timestamp}][{logEvent.Level}][{programId}]{logEvent.RenderMessage()}";
if (logEvent.Properties.TryGetValue("Key", out var value) && value is ScalarValue sv && sv.Value is string rawValue)
{
message = $"[{logEvent.Timestamp}][{logEvent.Level}][{programId}][{rawValue}]: {logEvent.RenderMessage()}";
}
} else
{
var buffer = new StringWriter(new StringBuilder(256));
_formatter.Format(logEvent, buffer);
message = buffer.ToString();
}
} else
{
var buffer = new StringWriter(new StringBuilder(256));
_formatter.Format(logEvent, buffer);
if(!_errorLogMap.TryGetValue(logEvent.Level, out var handler))
{
return;
}
message = buffer.ToString();
handler(message);
}
if(!_errorLogMap.TryGetValue(logEvent.Level, out var handler))
public DebugErrorLogSink(ITextFormatter formatter = null)
{
return;
_formatter = formatter;
}
handler(message);
}
public DebugErrorLogSink(ITextFormatter formatter = null)
{
_formatter = formatter;
}
}

View File

@@ -1,73 +1,113 @@
using Serilog.Events;
using System;
using System;
using Serilog.Events;
using Log = PepperDash.Core.Debug;
namespace PepperDash.Core.Logging;
public static class DebugExtensions
namespace PepperDash.Core.Logging
{
public static void LogException(this IKeyed device, Exception ex, string message, params object[] args)
public static class DebugExtensions
{
Log.LogMessage(ex, message, device, args);
}
/// <summary>
/// LogException method
/// </summary>
public static void LogException(this IKeyed device, Exception ex, string message, params object[] args)
{
Log.LogMessage(ex, message, device: device, args);
}
public static void LogVerbose(this IKeyed device, Exception ex, string message, params object[] args)
{
Log.LogMessage(LogEventLevel.Verbose, ex, message, device, args);
}
/// <summary>
/// LogVerbose method
/// </summary>
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, string message, params object[] args)
{
Log.LogMessage(LogEventLevel.Verbose, device, message, args);
}
/// <summary>
/// LogVerbose method
/// </summary>
public static void LogVerbose(this IKeyed device, string message, params object[] args)
{
Log.LogVerbose(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);
}
/// <summary>
/// LogDebug method
/// </summary>
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, string message, params object[] args)
{
Log.LogMessage(LogEventLevel.Debug, device, message, args);
}
/// <summary>
/// LogDebug method
/// </summary>
public static void LogDebug(this IKeyed device, string message, params object[] args)
{
Log.LogDebug(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);
}
/// <summary>
/// LogInformation method
/// </summary>
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, string message, params object[] args)
{
Log.LogMessage(LogEventLevel.Information, device, message, args);
}
/// <summary>
/// LogInformation method
/// </summary>
public static void LogInformation(this IKeyed device, string message, params object[] args)
{
Log.LogInformation(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);
}
/// <summary>
/// LogWarning method
/// </summary>
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, string message, params object[] args)
{
Log.LogMessage(LogEventLevel.Warning, device, message, args);
}
/// <summary>
/// LogWarning method
/// </summary>
public static void LogWarning(this IKeyed device, string message, params object[] args)
{
Log.LogWarning(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);
}
/// <summary>
/// LogError method
/// </summary>
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, string message, params object[] args)
{
Log.LogMessage(LogEventLevel.Error, device, message, args);
}
/// <summary>
/// LogError method
/// </summary>
public static void LogError(this IKeyed device, string message, params object[] args)
{
Log.LogError(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);
}
/// <summary>
/// LogFatal method
/// </summary>
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, string message, params object[] args)
{
Log.LogMessage(LogEventLevel.Fatal, device, message, args);
/// <summary>
/// LogFatal method
/// </summary>
public static void LogFatal(this IKeyed device, string message, params object[] args)
{
Log.LogFatal(device, message, args);
}
}
}

View File

@@ -2,25 +2,25 @@
using Crestron.SimplSharp;
using Newtonsoft.Json;
namespace PepperDash.Core.Logging;
/// <summary>
/// Class to persist current Debug settings across program restarts
/// </summary>
namespace PepperDash.Core.Logging
{
/// <summary>
/// Represents a DebugContextCollection
/// </summary>
public class DebugContextCollection
{
/// <summary>
/// To prevent threading issues with the DeviceDebugSettings collection
/// </summary>
private readonly CCriticalSection _deviceDebugSettingsLock;
/// <summary>
/// To prevent threading issues with the DeviceDebugSettings collection
/// </summary>
private readonly CCriticalSection _deviceDebugSettingsLock;
[JsonProperty("items")] private readonly Dictionary<string, DebugContextItem> _items;
/// <summary>
/// Collection of the debug settings for each device where the dictionary key is the device key
/// </summary>
[JsonProperty("deviceDebugSettings")]
private Dictionary<string, object> DeviceDebugSettings { get; set; }
/// <summary>
/// Collection of the debug settings for each device where the dictionary key is the device key
/// </summary>
[JsonProperty("deviceDebugSettings")]
private Dictionary<string, object> DeviceDebugSettings { get; set; }
/// <summary>
@@ -28,8 +28,8 @@ namespace PepperDash.Core.Logging;
/// </summary>
public DebugContextCollection()
{
_deviceDebugSettingsLock = new CCriticalSection();
DeviceDebugSettings = new Dictionary<string, object>();
_deviceDebugSettingsLock = new CCriticalSection();
DeviceDebugSettings = new Dictionary<string, object>();
_items = new Dictionary<string, DebugContextItem>();
}
@@ -39,6 +39,9 @@ namespace PepperDash.Core.Logging;
/// </summary>
/// <param name="contextKey"></param>
/// <param name="level"></param>
/// <summary>
/// SetLevel method
/// </summary>
public void SetLevel(string contextKey, int level)
{
if (level < 0 || level > 2)
@@ -51,6 +54,9 @@ namespace PepperDash.Core.Logging;
/// </summary>
/// <param name="contextKey"></param>
/// <returns></returns>
/// <summary>
/// GetOrCreateItem method
/// </summary>
public DebugContextItem GetOrCreateItem(string contextKey)
{
if (!_items.ContainsKey(contextKey))
@@ -59,40 +65,46 @@ namespace PepperDash.Core.Logging;
}
/// <summary>
/// sets the settings for a device or creates a new entry
/// </summary>
/// <param name="deviceKey"></param>
/// <param name="settings"></param>
/// <returns></returns>
public void SetDebugSettingsForKey(string deviceKey, object settings)
{
try
/// <summary>
/// sets the settings for a device or creates a new entry
/// </summary>
/// <param name="deviceKey"></param>
/// <param name="settings"></param>
/// <returns></returns>
/// <summary>
/// SetDebugSettingsForKey method
/// </summary>
public void SetDebugSettingsForKey(string deviceKey, object settings)
{
_deviceDebugSettingsLock.Enter();
if (DeviceDebugSettings.ContainsKey(deviceKey))
try
{
DeviceDebugSettings[deviceKey] = settings;
}
else
DeviceDebugSettings.Add(deviceKey, settings);
}
finally
{
_deviceDebugSettingsLock.Leave();
}
}
_deviceDebugSettingsLock.Enter();
/// <summary>
/// Gets the device settings for a device by key or returns null
/// </summary>
/// <param name="deviceKey"></param>
/// <returns></returns>
public object GetDebugSettingsForKey(string deviceKey)
{
return DeviceDebugSettings[deviceKey];
}
if (DeviceDebugSettings.ContainsKey(deviceKey))
{
DeviceDebugSettings[deviceKey] = settings;
}
else
DeviceDebugSettings.Add(deviceKey, settings);
}
finally
{
_deviceDebugSettingsLock.Leave();
}
}
/// <summary>
/// Gets the device settings for a device by key or returns null
/// </summary>
/// <param name="deviceKey"></param>
/// <returns></returns>
/// <summary>
/// GetDebugSettingsForKey method
/// </summary>
public object GetDebugSettingsForKey(string deviceKey)
{
return DeviceDebugSettings[deviceKey];
}
}
/// <summary>
@@ -100,15 +112,16 @@ namespace PepperDash.Core.Logging;
/// </summary>
public class DebugContextItem
{
/// <summary>
/// The level of debug messages to print
/// </summary>
/// <summary>
/// The level of debug messages to print
/// </summary>
[JsonProperty("level")]
public int Level { get; set; }
/// <summary>
/// Property to tell the program not to intitialize when it boots, if desired
/// </summary>
[JsonProperty("doNotLoadOnNextBoot")]
public bool DoNotLoadOnNextBoot { get; set; }
}
/// <summary>
/// Property to tell the program not to intitialize when it boots, if desired
/// </summary>
[JsonProperty("doNotLoadOnNextBoot")]
public bool DoNotLoadOnNextBoot { get; set; }
}
}

View File

@@ -1,332 +1,292 @@
using Crestron.SimplSharp;
using Org.BouncyCastle.Asn1.X509;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Serilog;
using Serilog.Configuration;
using Serilog.Core;
using Serilog.Events;
using Serilog.Formatting;
using Serilog.Formatting.Json;
using System;
using System.IO;
using System.Security.Authentication;
using WebSocketSharp;
using Serilog.Configuration;
using WebSocketSharp.Server;
using Crestron.SimplSharp;
using WebSocketSharp;
using System.Security.Authentication;
using WebSocketSharp.Net;
using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2;
using System.IO;
using Org.BouncyCastle.Asn1.X509;
using Serilog.Formatting;
using Newtonsoft.Json.Linq;
using Serilog.Formatting.Json;
namespace PepperDash.Core;
/// <summary>
/// Provides a WebSocket-based logging sink for debugging purposes, allowing log events to be broadcast to connected
/// WebSocket clients.
/// </summary>
/// <remarks>This class implements the <see cref="ILogEventSink"/> interface and is designed to send
/// formatted log events to WebSocket clients connected to a secure WebSocket server. The server is hosted locally
/// and uses a self-signed certificate for SSL/TLS encryption.</remarks>
public class DebugWebsocketSink : ILogEventSink, IKeyed
namespace PepperDash.Core
{
private HttpServer _httpsServer;
private readonly string _path = "/debug/join/";
private const string _certificateName = "selfCres";
private const string _certificatePassword = "cres12345";
/// <summary>
/// Gets the port number on which the HTTPS server is currently running.
/// <summary>
/// Represents a DebugWebsocketSink
/// </summary>
public int Port
{ get
{
if(_httpsServer == null) return 0;
return _httpsServer.Port;
}
}
/// <summary>
/// Gets the WebSocket URL for the current server instance.
/// </summary>
/// <remarks>The URL is dynamically constructed based on the server's current IP address, port,
/// and WebSocket path.</remarks>
public string Url
public class DebugWebsocketSink : ILogEventSink
{
get
{
if (_httpsServer == null) return "";
return $"wss://{CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)}:{_httpsServer.Port}{_httpsServer.WebSocketServices[_path].Path}";
}
}
private HttpServer _httpsServer;
private string _path = "/debug/join/";
private const string _certificateName = "selfCres";
private const string _certificatePassword = "cres12345";
/// <summary>
/// Gets a value indicating whether the HTTPS server is currently listening for incoming connections.
/// </summary>
public bool IsRunning { get => _httpsServer?.IsListening ?? false; }
/// <inheritdoc/>
public string Key => "DebugWebsocketSink";
private readonly ITextFormatter _textFormatter;
/// <summary>
/// Initializes a new instance of the <see cref="DebugWebsocketSink"/> class with the specified text formatter.
/// </summary>
/// <remarks>This constructor initializes the WebSocket sink and ensures that a certificate is
/// available for secure communication. If the required certificate does not exist, it will be created
/// automatically. Additionally, the sink is configured to stop the server when the program is
/// stopping.</remarks>
/// <param name="formatProvider">The text formatter used to format log messages. If null, a default JSON formatter is used.</param>
public DebugWebsocketSink(ITextFormatter formatProvider)
{
_textFormatter = formatProvider ?? new JsonFormatter();
if (!File.Exists($"\\user\\{_certificateName}.pfx"))
CreateCert();
CrestronEnvironment.ProgramStatusEventHandler += type =>
{
if (type == eProgramStatusEventType.Stopping)
{
StopServer();
}
};
}
private static void CreateCert()
{
try
{
var utility = new BouncyCertificate();
var ipAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
var hostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0);
var domainName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0);
CrestronConsole.PrintLine(string.Format("DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress));
var certificate = utility.CreateSelfSignedCertificate(string.Format("CN={0}.{1}", hostName, domainName), [string.Format("{0}.{1}", hostName, domainName), ipAddress], [KeyPurposeID.id_kp_serverAuth, KeyPurposeID.id_kp_clientAuth]);
//Crestron fails to let us do this...perhaps it should be done through their Dll's but haven't tested
var separator = Path.DirectorySeparatorChar;
utility.CertificatePassword = _certificatePassword;
utility.WriteCertificate(certificate, @$"{separator}user{separator}", _certificateName);
}
catch (Exception ex)
{
//Debug.Console(0, "WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace);
CrestronConsole.PrintLine("WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace);
}
}
/// <summary>
/// Sends a log event to all connected WebSocket clients.
/// </summary>
/// <remarks>The log event is formatted using the configured text formatter and then broadcasted
/// to all clients connected to the WebSocket server. If the WebSocket server is not initialized or not
/// listening, the method exits without performing any action.</remarks>
/// <param name="logEvent">The log event to be formatted and broadcasted. Cannot be null.</param>
public void Emit(LogEvent logEvent)
{
if (_httpsServer == null || !_httpsServer.IsListening) return;
var sw = new StringWriter();
_textFormatter.Format(logEvent, sw);
_httpsServer.WebSocketServices[_path].Sessions.Broadcast(sw.ToString());
}
/// <summary>
/// Starts the WebSocket server on the specified port and configures it with the appropriate certificate.
/// </summary>
/// <remarks>This method initializes the WebSocket server and binds it to the specified port. It
/// also applies the server's certificate for secure communication. Ensure that the port is not already in use
/// and that the certificate file is accessible.</remarks>
/// <param name="port">The port number on which the WebSocket server will listen. Must be a valid, non-negative port number.</param>
public void StartServerAndSetPort(int port)
{
Debug.Console(0, "Starting Websocket Server on port: {0}", port);
Start(port, $"\\user\\{_certificateName}.pfx", _certificatePassword);
}
private void Start(int port, string certPath = "", string certPassword = "")
{
try
{
_httpsServer = new HttpServer(port, true);
if (!string.IsNullOrWhiteSpace(certPath))
{
Debug.Console(0, "Assigning SSL Configuration");
_httpsServer.SslConfiguration.ServerCertificate = new X509Certificate2(certPath, certPassword);
_httpsServer.SslConfiguration.ClientCertificateRequired = false;
_httpsServer.SslConfiguration.CheckCertificateRevocation = false;
_httpsServer.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls12;
//this is just to test, you might want to actually validate
_httpsServer.SslConfiguration.ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
Debug.Console(0, "HTTPS ClientCerticateValidation Callback triggered");
return true;
};
}
Debug.Console(0, "Adding Debug Client Service");
_httpsServer.AddWebSocketService<DebugClient>(_path);
Debug.Console(0, "Assigning Log Info");
_httpsServer.Log.Level = LogLevel.Trace;
_httpsServer.Log.Output = (d, s) =>
{
uint level;
switch(d.Level)
{
case WebSocketSharp.LogLevel.Fatal:
level = 3;
break;
case WebSocketSharp.LogLevel.Error:
level = 2;
break;
case WebSocketSharp.LogLevel.Warn:
level = 1;
break;
case WebSocketSharp.LogLevel.Info:
level = 0;
break;
case WebSocketSharp.LogLevel.Debug:
level = 4;
break;
case WebSocketSharp.LogLevel.Trace:
level = 5;
break;
default:
level = 4;
break;
}
public int Port
{ get
{
Debug.Console(level, "{1} {0}\rCaller:{2}\rMessage:{3}\rs:{4}", d.Level.ToString(), d.Date.ToString(), d.Caller.ToString(), d.Message, s);
if(_httpsServer == null) return 0;
return _httpsServer.Port;
}
}
public string Url
{
get
{
if (_httpsServer == null) return "";
return $"wss://{CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)}:{_httpsServer.Port}{_httpsServer.WebSocketServices[_path].Path}";
}
}
/// <summary>
/// Gets or sets the IsRunning
/// </summary>
public bool IsRunning { get => _httpsServer?.IsListening ?? false; }
private readonly ITextFormatter _textFormatter;
public DebugWebsocketSink(ITextFormatter formatProvider)
{
_textFormatter = formatProvider ?? new JsonFormatter();
if (!File.Exists($"\\user\\{_certificateName}.pfx"))
CreateCert(null);
CrestronEnvironment.ProgramStatusEventHandler += type =>
{
if (type == eProgramStatusEventType.Stopping)
{
StopServer();
}
};
Debug.Console(0, "Starting");
_httpsServer.Start();
Debug.Console(0, "Ready");
}
catch (Exception ex)
private void CreateCert(string[] args)
{
Debug.Console(0, "WebSocket Failed to start {0}", ex.Message);
}
}
/// <summary>
/// Stops the WebSocket server if it is currently running.
/// </summary>
/// <remarks>This method halts the WebSocket server and releases any associated resources. After
/// calling this method, the server will no longer accept or process incoming connections.</remarks>
public void StopServer()
{
Debug.Console(0, "Stopping Websocket Server");
_httpsServer?.Stop();
_httpsServer = null;
}
}
/// <summary>
/// Configures the logger to write log events to a debug WebSocket sink.
/// </summary>
/// <remarks>This extension method allows you to direct log events to a WebSocket sink for debugging
/// purposes.</remarks>
public static class DebugWebsocketSinkExtensions
{
/// <summary>
/// Configures a logger to write log events to a debug WebSocket sink.
/// </summary>
/// <remarks>This method adds a sink that writes log events to a WebSocket for debugging purposes.
/// It is typically used during development to stream log events in real-time.</remarks>
/// <param name="loggerConfiguration">The logger sink configuration to apply the WebSocket sink to.</param>
/// <param name="formatProvider">An optional text formatter to format the log events. If not provided, a default formatter will be used.</param>
/// <returns>A <see cref="LoggerConfiguration"/> object that can be used to further configure the logger.</returns>
public static LoggerConfiguration DebugWebsocketSink(
this LoggerSinkConfiguration loggerConfiguration,
ITextFormatter formatProvider = null)
{
return loggerConfiguration.Sink(new DebugWebsocketSink(formatProvider));
}
}
/// <summary>
/// Represents a WebSocket client for debugging purposes, providing connection lifecycle management and message
/// handling functionality.
/// </summary>
/// <remarks>The <see cref="DebugClient"/> class extends <see cref="WebSocketBehavior"/> to handle
/// WebSocket connections, including events for opening, closing, receiving messages, and errors. It tracks the
/// duration of the connection and logs relevant events for debugging.</remarks>
public class DebugClient : WebSocketBehavior
{
private DateTime _connectionTime;
/// <summary>
/// Gets the duration of time the WebSocket connection has been active.
/// </summary>
public TimeSpan ConnectedDuration
{
get
{
if (Context.WebSocket.IsAlive)
try
{
return DateTime.Now - _connectionTime;
//Debug.Console(0,"CreateCert Creating Utility");
CrestronConsole.PrintLine("CreateCert Creating Utility");
//var utility = new CertificateUtility();
var utility = new BouncyCertificate();
//Debug.Console(0, "CreateCert Calling CreateCert");
CrestronConsole.PrintLine("CreateCert Calling CreateCert");
//utility.CreateCert();
var ipAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
var hostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0);
var domainName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0);
//Debug.Console(0, "DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress);
CrestronConsole.PrintLine(string.Format("DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress));
var certificate = utility.CreateSelfSignedCertificate(string.Format("CN={0}.{1}", hostName, domainName), new[] { string.Format("{0}.{1}", hostName, domainName), ipAddress }, new[] { KeyPurposeID.id_kp_serverAuth, KeyPurposeID.id_kp_clientAuth });
//Crestron fails to let us do this...perhaps it should be done through their Dll's but haven't tested
//Debug.Print($"CreateCert Storing Certificate To My.LocalMachine");
//utility.AddCertToStore(certificate, StoreName.My, StoreLocation.LocalMachine);
//Debug.Console(0, "CreateCert Saving Cert to \\user\\");
CrestronConsole.PrintLine("CreateCert Saving Cert to \\user\\");
utility.CertificatePassword = _certificatePassword;
utility.WriteCertificate(certificate, @"\user\", _certificateName);
//Debug.Console(0, "CreateCert Ending CreateCert");
CrestronConsole.PrintLine("CreateCert Ending CreateCert");
}
else
catch (Exception ex)
{
return new TimeSpan(0);
//Debug.Console(0, "WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace);
CrestronConsole.PrintLine(string.Format("WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace));
}
}
/// <summary>
/// Emit method
/// </summary>
public void Emit(LogEvent logEvent)
{
if (_httpsServer == null || !_httpsServer.IsListening) return;
var sw = new StringWriter();
_textFormatter.Format(logEvent, sw);
_httpsServer.WebSocketServices.Broadcast(sw.ToString());
}
/// <summary>
/// StartServerAndSetPort method
/// </summary>
public void StartServerAndSetPort(int port)
{
Debug.Console(0, "Starting Websocket Server on port: {0}", port);
Start(port, $"\\user\\{_certificateName}.pfx", _certificatePassword);
}
private void Start(int port, string certPath = "", string certPassword = "")
{
try
{
_httpsServer = new HttpServer(port, true);
if (!string.IsNullOrWhiteSpace(certPath))
{
Debug.Console(0, "Assigning SSL Configuration");
_httpsServer.SslConfiguration = new ServerSslConfiguration(new X509Certificate2(certPath, certPassword))
{
ClientCertificateRequired = false,
CheckCertificateRevocation = false,
EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls,
//this is just to test, you might want to actually validate
ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
Debug.Console(0, "HTTPS ClientCerticateValidation Callback triggered");
return true;
}
};
}
Debug.Console(0, "Adding Debug Client Service");
_httpsServer.AddWebSocketService<DebugClient>(_path);
Debug.Console(0, "Assigning Log Info");
_httpsServer.Log.Level = LogLevel.Trace;
_httpsServer.Log.Output = (d, s) =>
{
uint level;
switch(d.Level)
{
case WebSocketSharp.LogLevel.Fatal:
level = 3;
break;
case WebSocketSharp.LogLevel.Error:
level = 2;
break;
case WebSocketSharp.LogLevel.Warn:
level = 1;
break;
case WebSocketSharp.LogLevel.Info:
level = 0;
break;
case WebSocketSharp.LogLevel.Debug:
level = 4;
break;
case WebSocketSharp.LogLevel.Trace:
level = 5;
break;
default:
level = 4;
break;
}
Debug.Console(level, "{1} {0}\rCaller:{2}\rMessage:{3}\rs:{4}", d.Level.ToString(), d.Date.ToString(), d.Caller.ToString(), d.Message, s);
};
Debug.Console(0, "Starting");
_httpsServer.Start();
Debug.Console(0, "Ready");
}
catch (Exception ex)
{
Debug.Console(0, "WebSocket Failed to start {0}", ex.Message);
}
}
/// <summary>
/// StopServer method
/// </summary>
public void StopServer()
{
Debug.Console(0, "Stopping Websocket Server");
_httpsServer?.Stop();
_httpsServer = null;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="DebugClient"/> class.
public static class DebugWebsocketSinkExtensions
{
/// <summary>
/// DebugWebsocketSink method
/// </summary>
public static LoggerConfiguration DebugWebsocketSink(
this LoggerSinkConfiguration loggerConfiguration,
ITextFormatter formatProvider = null)
{
return loggerConfiguration.Sink(new DebugWebsocketSink(formatProvider));
}
}
/// <summary>
/// Represents a DebugClient
/// </summary>
/// <remarks>This constructor creates a new <see cref="DebugClient"/> instance and logs its
/// creation using the <see cref="Debug.Console(int, string)"/> method with a debug level of 0.</remarks>
public DebugClient()
public class DebugClient : WebSocketBehavior
{
Debug.Console(0, "DebugClient Created");
}
private DateTime _connectionTime;
/// <inheritdoc/>
protected override void OnOpen()
{
base.OnOpen();
public TimeSpan ConnectedDuration
{
get
{
if (Context.WebSocket.IsAlive)
{
return DateTime.Now - _connectionTime;
}
else
{
return new TimeSpan(0);
}
}
}
var url = Context.WebSocket.Url;
Debug.Console(0, Debug.ErrorLogLevel.Notice, "New WebSocket Connection from: {0}", url);
public DebugClient()
{
Debug.Console(0, "DebugClient Created");
}
_connectionTime = DateTime.Now;
}
protected override void OnOpen()
{
base.OnOpen();
/// <inheritdoc/>
protected override void OnMessage(MessageEventArgs e)
{
base.OnMessage(e);
var url = Context.WebSocket.Url;
Debug.Console(0, Debug.ErrorLogLevel.Notice, "New WebSocket Connection from: {0}", url);
Debug.Console(0, "WebSocket UiClient Message: {0}", e.Data);
}
_connectionTime = DateTime.Now;
}
/// <inheritdoc/>
protected override void OnClose(CloseEventArgs e)
{
base.OnClose(e);
protected override void OnMessage(MessageEventArgs e)
{
base.OnMessage(e);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Closing: {0} reason: {1}", e.Code, e.Reason);
Debug.Console(0, "WebSocket UiClient Message: {0}", e.Data);
}
}
protected override void OnClose(CloseEventArgs e)
{
base.OnClose(e);
/// <inheritdoc/>
protected override void OnError(WebSocketSharp.ErrorEventArgs e)
{
base.OnError(e);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Closing: {0} reason: {1}", e.Code, e.Reason);
Debug.Console(2, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Error: {0} message: {1}", e.Exception, e.Message);
}
protected override void OnError(WebSocketSharp.ErrorEventArgs e)
{
base.OnError(e);
Debug.Console(2, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Error: {0} message: {1}", e.Exception, e.Message);
}
}
}

View File

@@ -4,17 +4,19 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core;
/// <summary>
/// Not in use
/// </summary>
public static class NetworkComm
{
namespace PepperDash.Core
{
/// <summary>
/// Not in use
/// </summary>
public static class NetworkComm
{
/// <summary>
/// Not in use
/// </summary>
static NetworkComm()
{
}
}
}
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement;
namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// JSON password configuration
/// </summary>
@@ -22,4 +22,5 @@ namespace PepperDash.Core.PasswordManagement;
{
}
}
}
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement;
namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// Constants
/// </summary>
@@ -53,4 +53,5 @@ namespace PepperDash.Core.PasswordManagement;
/// Generic string value change constant
/// </summary>
public const ushort StringValueChange = 201;
}
}
}

View File

@@ -1,10 +1,10 @@
using System;
namespace PepperDash.Core.PasswordManagement;
/// <summary>
/// A class to allow user interaction with the PasswordManager
/// </summary>
namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// Represents a PasswordClient
/// </summary>
public class PasswordClient
{
/// <summary>
@@ -59,6 +59,9 @@ namespace PepperDash.Core.PasswordManagement;
/// Retrieve password by index
/// </summary>
/// <param name="key"></param>
/// <summary>
/// GetPasswordByIndex method
/// </summary>
public void GetPasswordByIndex(ushort key)
{
OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange);
@@ -81,6 +84,9 @@ namespace PepperDash.Core.PasswordManagement;
/// Password validation method
/// </summary>
/// <param name="password"></param>
/// <summary>
/// ValidatePassword method
/// </summary>
public void ValidatePassword(string password)
{
if (string.IsNullOrEmpty(password))
@@ -99,6 +105,9 @@ namespace PepperDash.Core.PasswordManagement;
/// password against the selected password when the length of the 2 are equal
/// </summary>
/// <param name="data"></param>
/// <summary>
/// BuildPassword method
/// </summary>
public void BuildPassword(string data)
{
PasswordToValidate = String.Concat(PasswordToValidate, data);
@@ -108,9 +117,9 @@ namespace PepperDash.Core.PasswordManagement;
ValidatePassword(PasswordToValidate);
}
/// <summary>
/// Clears the user entered password and resets the LEDs
/// </summary>
/// <summary>
/// ClearPassword method
/// </summary>
public void ClearPassword()
{
PasswordToValidate = "";
@@ -183,4 +192,5 @@ namespace PepperDash.Core.PasswordManagement;
GetPasswordByIndex(args.Index);
}
}
}
}
}

View File

@@ -2,11 +2,11 @@
using System.Collections.Generic;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement;
/// <summary>
/// Allows passwords to be stored and managed
/// </summary>
namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// Represents a PasswordManager
/// </summary>
public class PasswordManager
{
/// <summary>
@@ -71,6 +71,9 @@ namespace PepperDash.Core.PasswordManagement;
/// </summary>
/// <param name="key"></param>
/// <param name="password"></param>
/// <summary>
/// UpdatePassword method
/// </summary>
public void UpdatePassword(ushort key, string password)
{
// validate the parameters
@@ -152,6 +155,9 @@ namespace PepperDash.Core.PasswordManagement;
/// Method to change the default timer value, (default 5000ms/5s)
/// </summary>
/// <param name="time"></param>
/// <summary>
/// PasswordTimerMs method
/// </summary>
public void PasswordTimerMs(ushort time)
{
PasswordTimerElapsedMs = Convert.ToInt64(time);
@@ -190,7 +196,7 @@ namespace PepperDash.Core.PasswordManagement;
/// <summary>
/// Protected ushort change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnUshrtChange(ushort value, ushort index, ushort type)
@@ -237,4 +243,5 @@ namespace PepperDash.Core.PasswordManagement;
PasswordChange(this, args);
}
}
}
}
}

View File

@@ -5,7 +5,7 @@
<PropertyGroup>
<RootNamespace>PepperDash.Core</RootNamespace>
<AssemblyName>PepperDashCore</AssemblyName>
<TargetFramework>net8</TargetFramework>
<TargetFramework>net472</TargetFramework>
<Deterministic>true</Deterministic>
<NeutralLanguage>en</NeutralLanguage>
<OutputPath>bin\$(Configuration)\</OutputPath>
@@ -35,18 +35,22 @@
<EmbeddedResource Remove="Properties\**" />
<None Remove="lib\**" />
<None Remove="Properties\**" />
</ItemGroup>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.1" />
<PackageReference Include="Crestron.SimplSharp.SDK.Library" Version="2.21.128" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog" Version="4.3.0" />
<PackageReference Include="Serilog.Expressions" Version="5.0.0" />
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageReference Include="SSH.NET" Version="2025.0.0" />
<PackageReference Include="WebSocketSharp-netstandard" Version="1.0.1" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
<PackageReference Include="Crestron.SimplSharp.SDK.Library" Version="2.21.90" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.Expressions" Version="4.0.0" />
<PackageReference Include="Serilog.Formatting.Compact" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="SSH.NET" Version="2024.2.0" />
<PackageReference Include="WebSocketSharp" Version="1.0.3-rc11" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net6'">
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

View File

@@ -4,87 +4,87 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.SystemInfo;
namespace PepperDash.Core.SystemInfo
{
/// <summary>
/// Constants
/// </summary>
public class SystemInfoConstants
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public const ushort BoolValueChange = 1;
/// <summary>
///
/// </summary>
public const ushort CompleteBoolChange = 2;
public const ushort CompleteBoolChange = 2;
/// <summary>
///
/// </summary>
public const ushort BusyBoolChange = 3;
/// <summary>
///
/// </summary>
public const ushort BusyBoolChange = 3;
/// <summary>
///
/// </summary>
public const ushort UshortValueChange = 101;
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public const ushort StringValueChange = 201;
/// <summary>
///
/// </summary>
public const ushort ConsoleResponseChange = 202;
public const ushort ConsoleResponseChange = 202;
/// <summary>
///
/// </summary>
public const ushort ProcessorUptimeChange = 203;
public const ushort ProcessorUptimeChange = 203;
/// <summary>
///
/// </summary>
public const ushort ProgramUptimeChange = 204;
public const ushort ProgramUptimeChange = 204;
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public const ushort ObjectChange = 301;
/// <summary>
///
/// </summary>
public const ushort ProcessorConfigChange = 302;
public const ushort ProcessorConfigChange = 302;
/// <summary>
///
/// </summary>
public const ushort EthernetConfigChange = 303;
public const ushort EthernetConfigChange = 303;
/// <summary>
///
/// </summary>
public const ushort ControlSubnetConfigChange = 304;
public const ushort ControlSubnetConfigChange = 304;
/// <summary>
///
/// </summary>
public const ushort ProgramConfigChange = 305;
public const ushort ProgramConfigChange = 305;
}
/// <summary>
/// Processor Change Event Args Class
/// </summary>
/// <summary>
/// Represents a ProcessorChangeEventArgs
/// </summary>
public class ProcessorChangeEventArgs : EventArgs
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ProcessorInfo Processor { get; set; }
/// <summary>
///
/// </summary>
public ushort Type { get; set; }
public ushort Type { get; set; }
/// <summary>
///
/// </summary>
public ushort Index { get; set; }
public ushort Index { get; set; }
/// <summary>
/// Constructor
@@ -114,23 +114,23 @@ namespace PepperDash.Core.SystemInfo;
}
}
/// <summary>
/// Ethernet Change Event Args Class
/// </summary>
/// <summary>
/// Represents a EthernetChangeEventArgs
/// </summary>
public class EthernetChangeEventArgs : EventArgs
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public EthernetInfo Adapter { get; set; }
/// <summary>
///
/// </summary>
public ushort Type { get; set; }
public ushort Type { get; set; }
/// <summary>
///
/// </summary>
public ushort Index { get; set; }
public ushort Index { get; set; }
/// <summary>
/// Constructor
@@ -143,7 +143,7 @@ namespace PepperDash.Core.SystemInfo;
/// <summary>
/// Constructor overload
/// </summary>
/// <param name="ethernet"></param>
/// <param name="ethernet"></param>
/// <param name="type"></param>
public EthernetChangeEventArgs(EthernetInfo ethernet, ushort type)
{
@@ -154,9 +154,9 @@ namespace PepperDash.Core.SystemInfo;
/// <summary>
/// Constructor overload
/// </summary>
/// <param name="ethernet"></param>
/// <param name="ethernet"></param>
/// <param name="type"></param>
/// <param name="index"></param>
/// <param name="index"></param>
public EthernetChangeEventArgs(EthernetInfo ethernet, ushort type, ushort index)
{
Adapter = ethernet;
@@ -165,23 +165,23 @@ namespace PepperDash.Core.SystemInfo;
}
}
/// <summary>
/// Control Subnet Chage Event Args Class
/// </summary>
/// <summary>
/// Represents a ControlSubnetChangeEventArgs
/// </summary>
public class ControlSubnetChangeEventArgs : EventArgs
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ControlSubnetInfo Adapter { get; set; }
/// <summary>
///
/// </summary>
public ushort Type { get; set; }
public ushort Type { get; set; }
/// <summary>
///
/// </summary>
public ushort Index { get; set; }
public ushort Index { get; set; }
/// <summary>
/// Constructor
@@ -211,23 +211,23 @@ namespace PepperDash.Core.SystemInfo;
}
}
/// <summary>
/// Program Change Event Args Class
/// </summary>
/// <summary>
/// Represents a ProgramChangeEventArgs
/// </summary>
public class ProgramChangeEventArgs : EventArgs
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ProgramInfo Program { get; set; }
/// <summary>
///
/// </summary>
public ushort Type { get; set; }
public ushort Type { get; set; }
/// <summary>
///
/// </summary>
public ushort Index { get; set; }
public ushort Index { get; set; }
/// <summary>
/// Constructor
@@ -240,7 +240,7 @@ namespace PepperDash.Core.SystemInfo;
/// <summary>
/// Constructor overload
/// </summary>
/// <param name="program"></param>
/// <param name="program"></param>
/// <param name="type"></param>
public ProgramChangeEventArgs(ProgramInfo program, ushort type)
{
@@ -251,13 +251,14 @@ namespace PepperDash.Core.SystemInfo;
/// <summary>
/// Constructor overload
/// </summary>
/// <param name="program"></param>
/// <param name="program"></param>
/// <param name="type"></param>
/// <param name="index"></param>
/// <param name="index"></param>
public ProgramChangeEventArgs(ProgramInfo program, ushort type, ushort index)
{
Program = program;
Type = type;
Index = index;
}
}
}
}

View File

@@ -4,52 +4,52 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.SystemInfo;
namespace PepperDash.Core.SystemInfo
{
/// <summary>
/// Processor info class
/// </summary>
public class ProcessorInfo
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Model { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string SerialNumber { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Firmware { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string FirmwareDate { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string OsVersion { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string RuntimeEnvironment { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string DevicePlatform { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string ModuleDirectory { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string LocalTimeZone { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string ProgramIdTag { get; set; }
/// <summary>
@@ -66,45 +66,45 @@ namespace PepperDash.Core.SystemInfo;
/// </summary>
public class EthernetInfo
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ushort DhcpIsOn { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Hostname { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string MacAddress { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string IpAddress { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Subnet { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Gateway { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Dns1 { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Dns2 { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Dns3 { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Domain { get; set; }
/// <summary>
@@ -121,29 +121,29 @@ namespace PepperDash.Core.SystemInfo;
/// </summary>
public class ControlSubnetInfo
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ushort Enabled { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public ushort IsInAutomaticMode { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string MacAddress { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string IpAddress { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Subnet { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string RouterPrefix { get; set; }
/// <summary>
@@ -160,37 +160,37 @@ namespace PepperDash.Core.SystemInfo;
/// </summary>
public class ProgramInfo
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Name { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Header { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string System { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string ProgramIdTag { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string CompileTime { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Database { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Environment { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public string Programmer { get; set; }
/// <summary>
@@ -200,4 +200,5 @@ namespace PepperDash.Core.SystemInfo;
{
}
}
}
}

View File

@@ -4,37 +4,37 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.SystemInfo;
namespace PepperDash.Core.SystemInfo
{
/// <summary>
/// System Info class
/// </summary>
public class SystemInfoToSimpl
{
/// <summary>
/// Notifies of bool change
/// </summary>
/// <summary>
/// Notifies of bool change
/// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary>
/// Notifies of string change
/// </summary>
/// <summary>
/// Notifies of string change
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// Notifies of processor change
/// </summary>
/// <summary>
/// Notifies of processor change
/// </summary>
public event EventHandler<ProcessorChangeEventArgs> ProcessorChange;
/// <summary>
/// Notifies of ethernet change
/// </summary>
/// <summary>
/// Notifies of ethernet change
/// </summary>
public event EventHandler<EthernetChangeEventArgs> EthernetChange;
/// <summary>
/// Notifies of control subnet change
/// </summary>
/// <summary>
/// Notifies of control subnet change
/// </summary>
public event EventHandler<ControlSubnetChangeEventArgs> ControlSubnetChange;
/// <summary>
/// Notifies of program change
/// </summary>
/// <summary>
/// Notifies of program change
/// </summary>
public event EventHandler<ProgramChangeEventArgs> ProgramChange;
/// <summary>
@@ -100,9 +100,9 @@ namespace PepperDash.Core.SystemInfo;
OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange);
}
/// <summary>
/// Gets the current ethernet info
/// </summary>
/// <summary>
/// GetEthernetInfo method
/// </summary>
public void GetEthernetInfo()
{
OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange);
@@ -161,9 +161,9 @@ namespace PepperDash.Core.SystemInfo;
OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange);
}
/// <summary>
/// Gets the current control subnet info
/// </summary>
/// <summary>
/// GetControlSubnetInfo method
/// </summary>
public void GetControlSubnetInfo()
{
OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange);
@@ -206,6 +206,9 @@ namespace PepperDash.Core.SystemInfo;
/// Gets the program info by index
/// </summary>
/// <param name="index"></param>
/// <summary>
/// GetProgramInfoByIndex method
/// </summary>
public void GetProgramInfoByIndex(ushort index)
{
if (index < 1 || index > 10)
@@ -263,9 +266,9 @@ namespace PepperDash.Core.SystemInfo;
OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange);
}
/// <summary>
/// Gets the processor uptime and passes it to S+
/// </summary>
/// <summary>
/// RefreshProcessorUptime method
/// </summary>
public void RefreshProcessorUptime()
{
try
@@ -287,6 +290,9 @@ namespace PepperDash.Core.SystemInfo;
/// Gets the program uptime, by index, and passes it to S+
/// </summary>
/// <param name="index"></param>
/// <summary>
/// RefreshProgramUptimeByIndex method
/// </summary>
public void RefreshProgramUptimeByIndex(int index)
{
try
@@ -308,6 +314,9 @@ namespace PepperDash.Core.SystemInfo;
/// Sends command to console, passes response back using string change event
/// </summary>
/// <param name="cmd"></param>
/// <summary>
/// SendConsoleCommand method
/// </summary>
public void SendConsoleCommand(string cmd)
{
if (string.IsNullOrEmpty(cmd))
@@ -327,10 +336,10 @@ namespace PepperDash.Core.SystemInfo;
/// <summary>
/// private method to parse console messages
/// </summary>
/// <param name="data"></param>
/// <param name="data"></param>
/// <param name="line"></param>
/// <param name="dataStart"></param>
/// <param name="dataEnd"></param>
/// <param name="dataStart"></param>
/// <param name="dataEnd"></param>
/// <returns></returns>
private string ParseConsoleResponse(string data, string line, string dataStart, string dataEnd)
{
@@ -458,4 +467,5 @@ namespace PepperDash.Core.SystemInfo;
ProgramChange(this, args);
}
}
}
}
}

View File

@@ -20,336 +20,352 @@ using Org.BouncyCastle.Crypto.Operators;
using BigInteger = Org.BouncyCastle.Math.BigInteger;
using X509Certificate = Org.BouncyCastle.X509.X509Certificate;
namespace PepperDash.Core;
/// <summary>
/// Taken From https://github.com/rlipscombe/bouncy-castle-csharp/
/// </summary>
internal class BouncyCertificate
namespace PepperDash.Core
{
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;
}
/// <summary>
/// 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.
/// Taken From https://github.com/rlipscombe/bouncy-castle-csharp/
/// </summary>
/// <param name="random"></param>
/// <returns></returns>
private BigInteger GenerateSerialNumber(SecureRandom random)
internal class BouncyCertificate
{
var serialNumber =
BigIntegers.CreateRandomInRange(
BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
return serialNumber;
}
/// <summary>
/// Generate a key pair.
/// </summary>
/// <param name="random">The random number generator.</param>
/// <param name="strength">The key length in bits. For RSA, 2048 bits should be considered the minimum acceptable these days.</param>
/// <returns></returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="issuerDN"></param>
/// <param name="issuerKeyPair"></param>
/// <param name="issuerSerialNumber"></param>
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);
}
/// <summary>
/// Add the "Subject Alternative Names" extension. Note that you have to repeat
/// the value from the "Subject Name" property.
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="subjectAlternativeNames"></param>
private void AddSubjectAlternativeNames(X509V3CertificateGenerator certificateGenerator,
IEnumerable<string> subjectAlternativeNames)
{
var subjectAlternativeNamesExtension =
new DerSequence(
subjectAlternativeNames.Select(name => new GeneralName(GeneralName.DnsName, name))
.ToArray<Asn1Encodable>());
certificateGenerator.AddExtension(
X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension);
}
/// <summary>
/// Add the "Extended Key Usage" extension, specifying (for example) "server authentication".
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="usages"></param>
private void AddExtendedKeyUsage(X509V3CertificateGenerator certificateGenerator, KeyPurposeID[] usages)
{
certificateGenerator.AddExtension(
X509Extensions.ExtendedKeyUsage.Id, false, new ExtendedKeyUsage(usages));
}
/// <summary>
/// Add the "Basic Constraints" extension.
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="isCertificateAuthority"></param>
private void AddBasicConstraints(X509V3CertificateGenerator certificateGenerator,
bool isCertificateAuthority)
{
certificateGenerator.AddExtension(
X509Extensions.BasicConstraints.Id, true, new BasicConstraints(isCertificateAuthority));
}
/// <summary>
/// Add the Subject Key Identifier.
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="subjectKeyPair"></param>
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
public string CertificatePassword { get; set; } = "password";
public X509Certificate2 LoadCertificate(string issuerFileName, string password)
{
var pfx = certificate.Export(X509ContentType.Pfx, CertificatePassword);
File.WriteAllBytes(string.Format("{0}.pfx", Path.Combine(outputDirectory, certName)), pfx);
// We need to pass 'Exportable', otherwise we can't get the private key.
var issuerCertificate = new X509Certificate2(issuerFileName, password, X509KeyStorageFlags.Exportable);
return issuerCertificate;
}
catch (Exception ex)
/// <summary>
/// IssueCertificate method
/// </summary>
public X509Certificate2 IssueCertificate(string subjectName, X509Certificate2 issuerCertificate, string[] subjectAlternativeNames, KeyPurposeID[] usages)
{
CrestronConsole.PrintLine(string.Format("Failed to write x509 cert pfx\r\n{0}", ex.Message));
// 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);
}
// Create Base 64 encoded CER (public key only)
using (var writer = new StreamWriter($"{Path.Combine(outputDirectory, certName)}.cer", false))
/// <summary>
/// CreateCertificateAuthorityCertificate method
/// </summary>
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);
}
/// <summary>
/// CreateSelfSignedCertificate method
/// </summary>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="random"></param>
/// <returns></returns>
private BigInteger GenerateSerialNumber(SecureRandom random)
{
var serialNumber =
BigIntegers.CreateRandomInRange(
BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
return serialNumber;
}
/// <summary>
/// Generate a key pair.
/// </summary>
/// <param name="random">The random number generator.</param>
/// <param name="strength">The key length in bits. For RSA, 2048 bits should be considered the minimum acceptable these days.</param>
/// <returns></returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="issuerDN"></param>
/// <param name="issuerKeyPair"></param>
/// <param name="issuerSerialNumber"></param>
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);
}
/// <summary>
/// Add the "Subject Alternative Names" extension. Note that you have to repeat
/// the value from the "Subject Name" property.
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="subjectAlternativeNames"></param>
private void AddSubjectAlternativeNames(X509V3CertificateGenerator certificateGenerator,
IEnumerable<string> subjectAlternativeNames)
{
var subjectAlternativeNamesExtension =
new DerSequence(
subjectAlternativeNames.Select(name => new GeneralName(GeneralName.DnsName, name))
.ToArray<Asn1Encodable>());
certificateGenerator.AddExtension(
X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension);
}
/// <summary>
/// Add the "Extended Key Usage" extension, specifying (for example) "server authentication".
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="usages"></param>
private void AddExtendedKeyUsage(X509V3CertificateGenerator certificateGenerator, KeyPurposeID[] usages)
{
certificateGenerator.AddExtension(
X509Extensions.ExtendedKeyUsage.Id, false, new ExtendedKeyUsage(usages));
}
/// <summary>
/// Add the "Basic Constraints" extension.
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="isCertificateAuthority"></param>
private void AddBasicConstraints(X509V3CertificateGenerator certificateGenerator,
bool isCertificateAuthority)
{
certificateGenerator.AddExtension(
X509Extensions.BasicConstraints.Id, true, new BasicConstraints(isCertificateAuthority));
}
/// <summary>
/// Add the Subject Key Identifier.
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="subjectKeyPair"></param>
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;
}
/// <summary>
/// WriteCertificate method
/// </summary>
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 contents = string.Format("-----BEGIN CERTIFICATE-----\r\n{0}\r\n-----END CERTIFICATE-----", Convert.ToBase64String(certificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks));
writer.Write(contents);
var pfx = certificate.Export(X509ContentType.Pfx, CertificatePassword);
File.WriteAllBytes(string.Format("{0}.pfx", Path.Combine(outputDirectory, certName)), pfx);
}
catch (Exception ex)
{
CrestronConsole.PrintLine(string.Format("Failed to write x509 cert cer\r\n{0}", ex.Message));
CrestronConsole.PrintLine(string.Format("Failed to write x509 cert pfx\r\n{0}", ex.Message));
}
// Create Base 64 encoded CER (public key only)
using (var writer = new StreamWriter($"{Path.Combine(outputDirectory, certName)}.cer", false))
{
try
{
var contents = string.Format("-----BEGIN CERTIFICATE-----\r\n{0}\r\n-----END CERTIFICATE-----", Convert.ToBase64String(certificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks));
writer.Write(contents);
}
catch (Exception ex)
{
CrestronConsole.PrintLine(string.Format("Failed to write x509 cert cer\r\n{0}", ex.Message));
}
}
}
}
public bool AddCertToStore(X509Certificate2 cert, System.Security.Cryptography.X509Certificates.StoreName st, System.Security.Cryptography.X509Certificates.StoreLocation sl)
{
bool bRet = false;
try
/// <summary>
/// AddCertToStore method
/// </summary>
public bool AddCertToStore(X509Certificate2 cert, System.Security.Cryptography.X509Certificates.StoreName st, System.Security.Cryptography.X509Certificates.StoreLocation sl)
{
var store = new System.Security.Cryptography.X509Certificates.X509Store(st, sl);
store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadWrite);
store.Add(cert);
bool bRet = false;
store.Close();
bRet = true;
}
catch (Exception ex)
{
CrestronConsole.PrintLine(string.Format("AddCertToStore Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace));
}
try
{
var store = new System.Security.Cryptography.X509Certificates.X509Store(st, sl);
store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadWrite);
store.Add(cert);
return bRet;
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;
}
}
}

View File

@@ -1,10 +1,10 @@
using Crestron.SimplSharp.WebScripting;
namespace PepperDash.Core.Web.RequestHandlers;
/// <summary>
/// Web API default request handler
/// </summary>
namespace PepperDash.Core.Web.RequestHandlers
{
/// <summary>
/// Represents a DefaultRequestHandler
/// </summary>
public class DefaultRequestHandler : WebApiBaseRequestHandler
{
/// <summary>
@@ -13,4 +13,5 @@ namespace PepperDash.Core.Web.RequestHandlers;
public DefaultRequestHandler()
: base(true)
{ }
}
}
}

View File

@@ -3,160 +3,164 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace PepperDash.Core.Web.RequestHandlers;
public abstract class WebApiBaseRequestAsyncHandler:IHttpCwsHandler
namespace PepperDash.Core.Web.RequestHandlers
{
private readonly Dictionary<string, Func<HttpCwsContext, Task>> _handlers;
protected readonly bool EnableCors;
/// <summary>
/// Constructor
/// </summary>
protected WebApiBaseRequestAsyncHandler(bool enableCors)
public abstract class WebApiBaseRequestAsyncHandler:IHttpCwsHandler
{
EnableCors = enableCors;
private readonly Dictionary<string, Func<HttpCwsContext, Task>> _handlers;
protected readonly bool EnableCors;
_handlers = new Dictionary<string, Func<HttpCwsContext, Task>>
/// <summary>
/// Constructor
/// </summary>
protected WebApiBaseRequestAsyncHandler(bool enableCors)
{
{"CONNECT", HandleConnect},
{"DELETE", HandleDelete},
{"GET", HandleGet},
{"HEAD", HandleHead},
{"OPTIONS", HandleOptions},
{"PATCH", HandlePatch},
{"POST", HandlePost},
{"PUT", HandlePut},
{"TRACE", HandleTrace}
};
}
EnableCors = enableCors;
/// <summary>
/// Constructor
/// </summary>
protected WebApiBaseRequestAsyncHandler()
: this(false)
{
}
/// <summary>
/// Handles CONNECT method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleConnect(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles DELETE method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleDelete(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles GET method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleGet(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles HEAD method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleHead(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles OPTIONS method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleOptions(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles PATCH method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandlePatch(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles POST method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandlePost(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles PUT method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandlePut(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles TRACE method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleTrace(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Process request
/// </summary>
/// <param name="context"></param>
public void ProcessRequest(HttpCwsContext context)
{
if (!_handlers.TryGetValue(context.Request.HttpMethod, out Func<HttpCwsContext, Task> handler))
{
return;
_handlers = new Dictionary<string, Func<HttpCwsContext, Task>>
{
{"CONNECT", HandleConnect},
{"DELETE", HandleDelete},
{"GET", HandleGet},
{"HEAD", HandleHead},
{"OPTIONS", HandleOptions},
{"PATCH", HandlePatch},
{"POST", HandlePost},
{"PUT", HandlePut},
{"TRACE", HandleTrace}
};
}
if (EnableCors)
/// <summary>
/// Constructor
/// </summary>
protected WebApiBaseRequestAsyncHandler()
: this(false)
{
context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
context.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
}
var handlerTask = handler(context);
/// <summary>
/// Handles CONNECT method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleConnect(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
handlerTask.GetAwaiter().GetResult();
/// <summary>
/// Handles DELETE method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleDelete(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles GET method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleGet(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles HEAD method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleHead(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles OPTIONS method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleOptions(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles PATCH method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandlePatch(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles POST method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandlePost(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles PUT method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandlePut(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles TRACE method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleTrace(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Process request
/// </summary>
/// <param name="context"></param>
/// <summary>
/// ProcessRequest method
/// </summary>
public void ProcessRequest(HttpCwsContext context)
{
if (!_handlers.TryGetValue(context.Request.HttpMethod, out Func<HttpCwsContext, Task> 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();
}
}
}

View File

@@ -2,8 +2,8 @@
using System.Collections.Generic;
using Crestron.SimplSharp.WebScripting;
namespace PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Core.Web.RequestHandlers
{
/// <summary>
/// CWS Base Handler, implements IHttpCwsHandler
/// </summary>
@@ -144,6 +144,9 @@ namespace PepperDash.Core.Web.RequestHandlers;
/// Process request
/// </summary>
/// <param name="context"></param>
/// <summary>
/// ProcessRequest method
/// </summary>
public void ProcessRequest(HttpCwsContext context)
{
Action<HttpCwsContext> handler;
@@ -161,4 +164,5 @@ namespace PepperDash.Core.Web.RequestHandlers;
handler(context);
}
}
}
}

View File

@@ -7,8 +7,8 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Core.Web;
namespace PepperDash.Core.Web
{
/// <summary>
/// Web API server
/// </summary>
@@ -25,24 +25,24 @@ namespace PepperDash.Core.Web;
private readonly CCriticalSection _serverLock = new CCriticalSection();
private HttpCwsServer _server;
/// <summary>
/// Web API server key
/// </summary>
/// <summary>
/// Gets or sets the Key
/// </summary>
public string Key { get; private set; }
/// <summary>
/// Web API server name
/// </summary>
/// <summary>
/// Gets or sets the Name
/// </summary>
public string Name { get; private set; }
/// <summary>
/// CWS base path, will default to "/api" if not set via initialize method
/// </summary>
/// <summary>
/// Gets or sets the BasePath
/// </summary>
public string BasePath { get; private set; }
/// <summary>
/// Indicates CWS is registered with base path
/// </summary>
/// <summary>
/// Gets or sets the IsRegistered
/// </summary>
public bool IsRegistered { get; private set; }
/// <summary>
@@ -137,9 +137,9 @@ namespace PepperDash.Core.Web;
Start();
}
/// <summary>
/// Initializes CWS class
/// </summary>
/// <summary>
/// Initialize method
/// </summary>
public void Initialize(string key, string basePath)
{
Key = key;
@@ -165,6 +165,9 @@ namespace PepperDash.Core.Web;
/// Removes a route from CWS
/// </summary>
/// <param name="route"></param>
/// <summary>
/// RemoveRoute method
/// </summary>
public void RemoveRoute(HttpCwsRoute route)
{
if (route == null)
@@ -176,9 +179,9 @@ namespace PepperDash.Core.Web;
_server.Routes.Remove(route);
}
/// <summary>
/// Returns a list of the current routes
/// </summary>
/// <summary>
/// GetRouteCollection method
/// </summary>
public HttpCwsRouteCollection GetRouteCollection()
{
return _server.Routes;
@@ -222,9 +225,9 @@ namespace PepperDash.Core.Web;
}
}
/// <summary>
/// Stop CWS instance
/// </summary>
/// <summary>
/// Stop method
/// </summary>
public void Stop()
{
try
@@ -280,4 +283,5 @@ namespace PepperDash.Core.Web;
Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception InnerException: {0}", ex.InnerException);
}
}
}
}
}

View File

@@ -1,45 +1,45 @@
using System;
namespace PepperDash.Core.WebApi.Presets;
/// <summary>
/// Represents a preset
/// </summary>
namespace PepperDash.Core.WebApi.Presets
{
/// <summary>
/// Represents a Preset
/// </summary>
public class Preset
{
/// <summary>
/// ID of preset
/// </summary>
/// <summary>
/// ID of preset
/// </summary>
public int Id { get; set; }
/// <summary>
/// User ID
/// </summary>
/// <summary>
/// Gets or sets the UserId
/// </summary>
public int UserId { get; set; }
/// <summary>
/// Room Type ID
/// </summary>
/// <summary>
/// Gets or sets the RoomTypeId
/// </summary>
public int RoomTypeId { get; set; }
/// <summary>
/// Preset Name
/// </summary>
/// <summary>
/// Gets or sets the PresetName
/// </summary>
public string PresetName { get; set; }
/// <summary>
/// Preset Number
/// </summary>
/// <summary>
/// Gets or sets the PresetNumber
/// </summary>
public int PresetNumber { get; set; }
/// <summary>
/// Preset Data
/// </summary>
/// <summary>
/// Gets or sets the Data
/// </summary>
public string Data { get; set; }
/// <summary>
/// Constructor
/// </summary>
/// <summary>
/// Constructor
/// </summary>
public Preset()
{
PresetName = "";
@@ -48,39 +48,40 @@ namespace PepperDash.Core.WebApi.Presets;
}
}
/// <summary>
///
/// </summary>
/// <summary>
/// Represents a PresetReceivedEventArgs
/// </summary>
public class PresetReceivedEventArgs : EventArgs
{
/// <summary>
/// True when the preset is found
/// </summary>
public bool LookupSuccess { get; private set; }
/// <summary>
/// S+ helper
/// </summary>
public ushort ULookupSuccess { get { return (ushort)(LookupSuccess ? 1 : 0); } }
/// <summary>
/// True when the preset is found
/// </summary>
public bool LookupSuccess { get; private set; }
/// <summary>
/// Gets or sets the ULookupSuccess
/// </summary>
public ushort ULookupSuccess { get { return (ushort)(LookupSuccess ? 1 : 0); } }
/// <summary>
/// The preset
/// </summary>
public Preset Preset { get; private set; }
/// <summary>
/// Gets or sets the Preset
/// </summary>
public Preset Preset { get; private set; }
/// <summary>
/// For Simpl+
/// </summary>
public PresetReceivedEventArgs() { }
/// <summary>
/// Constructor
/// </summary>
/// <param name="preset"></param>
/// <param name="success"></param>
/// <summary>
/// Constructor
/// </summary>
/// <param name="preset"></param>
/// <param name="success"></param>
public PresetReceivedEventArgs(Preset preset, bool success)
{
LookupSuccess = success;
LookupSuccess = success;
Preset = preset;
}
}
}
}

View File

@@ -4,31 +4,31 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.WebApi.Presets;
namespace PepperDash.Core.WebApi.Presets
{
/// <summary>
///
/// </summary>
public class User
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public int Id { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the ExternalId
/// </summary>
public string ExternalId { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the FirstName
/// </summary>
public string FirstName { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the LastName
/// </summary>
public string LastName { get; set; }
}
@@ -38,19 +38,19 @@ namespace PepperDash.Core.WebApi.Presets;
/// </summary>
public class UserReceivedEventArgs : EventArgs
{
/// <summary>
/// True when user is found
/// </summary>
public bool LookupSuccess { get; private set; }
/// <summary>
/// True when user is found
/// </summary>
public bool LookupSuccess { get; private set; }
/// <summary>
/// For stupid S+
/// </summary>
public ushort ULookupSuccess { get { return (ushort)(LookupSuccess ? 1 : 0); } }
/// <summary>
/// Gets or sets the ULookupSuccess
/// </summary>
public ushort ULookupSuccess { get { return (ushort)(LookupSuccess ? 1 : 0); } }
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the User
/// </summary>
public User User { get; private set; }
/// <summary>
@@ -58,35 +58,36 @@ namespace PepperDash.Core.WebApi.Presets;
/// </summary>
public UserReceivedEventArgs() { }
/// <summary>
/// Constructor
/// </summary>
/// <param name="user"></param>
/// <param name="success"></param>
/// <summary>
/// Constructor
/// </summary>
/// <param name="user"></param>
/// <param name="success"></param>
public UserReceivedEventArgs(User user, bool success)
{
LookupSuccess = success;
LookupSuccess = success;
User = user;
}
}
/// <summary>
///
/// </summary>
/// <summary>
/// Represents a UserAndRoomMessage
/// </summary>
public class UserAndRoomMessage
{
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public int UserId { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the RoomTypeId
/// </summary>
public int RoomTypeId { get; set; }
/// <summary>
///
/// </summary>
/// <summary>
/// Gets or sets the PresetNumber
/// </summary>
public int PresetNumber { get; set; }
}
}
}

View File

@@ -8,26 +8,26 @@ using Newtonsoft.Json.Linq;
using PepperDash.Core.JsonToSimpl;
namespace PepperDash.Core.WebApi.Presets;
/// <summary>
/// Passcode client for the WebApi
/// </summary>
namespace PepperDash.Core.WebApi.Presets
{
/// <summary>
/// Passcode client for the WebApi
/// </summary>
public class WebApiPasscodeClient : IKeyed
{
/// <summary>
/// Notifies when user received
/// </summary>
/// <summary>
/// Notifies when user received
/// </summary>
public event EventHandler<UserReceivedEventArgs> UserReceived;
/// <summary>
/// Notifies when Preset received
/// </summary>
/// <summary>
/// Notifies when Preset received
/// </summary>
public event EventHandler<PresetReceivedEventArgs> PresetReceived;
/// <summary>
/// Unique identifier for this instance
/// </summary>
/// <summary>
/// Gets or sets the Key
/// </summary>
public string Key { get; private set; }
//string JsonMasterKey;
@@ -54,13 +54,13 @@ namespace PepperDash.Core.WebApi.Presets;
{
}
/// <summary>
/// Initializes the instance
/// </summary>
/// <param name="key"></param>
/// <param name="jsonMasterKey"></param>
/// <param name="urlBase"></param>
/// <param name="defaultPresetJsonFilePath"></param>
/// <summary>
/// Initializes the instance
/// </summary>
/// <param name="key"></param>
/// <param name="jsonMasterKey"></param>
/// <param name="urlBase"></param>
/// <param name="defaultPresetJsonFilePath"></param>
public void Initialize(string key, string jsonMasterKey, string urlBase, string defaultPresetJsonFilePath)
{
Key = key;
@@ -73,41 +73,44 @@ namespace PepperDash.Core.WebApi.Presets;
J2SMaster.Initialize(jsonMasterKey);
}
/// <summary>
/// Gets the user for a passcode
/// </summary>
/// <param name="passcode"></param>
/// <summary>
/// Gets the user for a passcode
/// </summary>
/// <param name="passcode"></param>
/// <summary>
/// GetUserForPasscode method
/// </summary>
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<User>(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<User>(resp.ContentString);
CurrentUser = user;
if (handler != null)
UserReceived(this, new UserReceivedEventArgs(user, true));
}
else
if (handler != null)
UserReceived(this, new UserReceivedEventArgs(null, false));
}
/// <summary>
@@ -115,6 +118,9 @@ namespace PepperDash.Core.WebApi.Presets;
/// </summary>
/// <param name="roomTypeId"></param>
/// <param name="presetNumber"></param>
/// <summary>
/// GetPresetForThisUser method
/// </summary>
public void GetPresetForThisUser(int roomTypeId, int presetNumber)
{
if (CurrentUser == null)
@@ -130,57 +136,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);
var client = new HttpsClient();
client.HostVerification = false;
client.PeerVerification = false;
// ask for the preset
var resp = client.Dispatch(req);
if (resp.Code == 200) // got it
{
//Debug.Console(1, this, "Received: {0}", resp.ContentString);
var preset = JsonConvert.DeserializeObject<Preset>(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();
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);
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));
}
var client = new HttpsClient();
client.HostVerification = false;
client.PeerVerification = false;
// ask for the preset
var resp = client.Dispatch(req);
if (resp.Code == 200) // got it
{
//Debug.Console(1, this, "Received: {0}", resp.ContentString);
var preset = JsonConvert.DeserializeObject<Preset>(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();
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));
}
}
@@ -212,6 +218,9 @@ namespace PepperDash.Core.WebApi.Presets;
/// </summary>
/// <param name="roomTypeId"></param>
/// <param name="presetNumber"></param>
/// <summary>
/// SavePresetForThisUser method
/// </summary>
public void SavePresetForThisUser(int roomTypeId, int presetNumber)
{
if (CurrentPreset == null)
@@ -236,8 +245,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));
@@ -246,8 +255,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);
@@ -270,3 +279,4 @@ namespace PepperDash.Core.WebApi.Presets;
}
}
}
}

View File

@@ -1,24 +1,25 @@
using System.Collections.Generic;
using PepperDash.Core.Intersystem.Tokens;
namespace PepperDash.Core.Intersystem.Serialization;
/// <summary>
/// Interface to determine XSig serialization for an object.
/// </summary>
public interface IXSigSerialization
namespace PepperDash.Core.Intersystem.Serialization
{
/// <summary>
/// Serialize the sig data
/// Interface to determine XSig serialization for an object.
/// </summary>
/// <returns></returns>
IEnumerable<XSigToken> Serialize();
public interface IXSigSerialization
{
/// <summary>
/// Serialize the sig data
/// </summary>
/// <returns></returns>
IEnumerable<XSigToken> Serialize();
/// <summary>
/// Deserialize the sig data
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tokens"></param>
/// <returns></returns>
T Deserialize<T>(IEnumerable<XSigToken> tokens) where T : class, IXSigSerialization;
/// <summary>
/// Deserialize the sig data
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tokens"></param>
/// <returns></returns>
T Deserialize<T>(IEnumerable<XSigToken> tokens) where T : class, IXSigSerialization;
}
}

View File

@@ -1,27 +1,28 @@
using System;
namespace PepperDash.Core.Intersystem.Serialization;
/// <summary>
/// Class to handle this specific exception type
/// </summary>
public class XSigSerializationException : Exception
namespace PepperDash.Core.Intersystem.Serialization
{
/// <summary>
/// default constructor
/// Class to handle this specific exception type
/// </summary>
public XSigSerializationException() { }
public class XSigSerializationException : Exception
{
/// <summary>
/// default constructor
/// </summary>
public XSigSerializationException() { }
/// <summary>
/// constructor with message
/// </summary>
/// <param name="message"></param>
public XSigSerializationException(string message) : base(message) { }
/// <summary>
/// constructor with message
/// </summary>
/// <param name="message"></param>
public XSigSerializationException(string message) : base(message) { }
/// <summary>
/// constructor with message and innner exception
/// </summary>
/// <param name="message"></param>
/// <param name="inner"></param>
public XSigSerializationException(string message, Exception inner) : base(message, inner) { }
/// <summary>
/// constructor with message and innner exception
/// </summary>
/// <param name="message"></param>
/// <param name="inner"></param>
public XSigSerializationException(string message, Exception inner) : base(message, inner) { }
}
}

View File

@@ -1,87 +1,98 @@
using System;
namespace PepperDash.Core.Intersystem.Tokens;
/// <summary>
/// Represents an XSigAnalogToken
/// </summary>
public sealed class XSigAnalogToken : XSigToken, IFormattable
namespace PepperDash.Core.Intersystem.Tokens
{
private readonly ushort _value;
/// <summary>
/// Constructor
/// Represents an XSigAnalogToken
/// </summary>
/// <param name="index"></param>
/// <param name="value"></param>
public XSigAnalogToken(int index, ushort value)
: base(index)
public sealed class XSigAnalogToken : XSigToken, IFormattable
{
// 10-bits available for analog encoded data
if (index >= 1024 || index < 0)
throw new ArgumentOutOfRangeException("index");
private readonly ushort _value;
_value = value;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="index"></param>
/// <param name="value"></param>
public XSigAnalogToken(int index, ushort value)
: base(index)
{
// 10-bits available for analog encoded data
if (index >= 1024 || index < 0)
throw new ArgumentOutOfRangeException("index");
/// <summary>
///
/// </summary>
public ushort Value
{
get { return _value; }
}
_value = value;
}
/// <summary>
///
/// </summary>
public override XSigTokenType TokenType
{
get { return XSigTokenType.Analog; }
}
/// <summary>
///
/// </summary>
public ushort Value
{
get { return _value; }
}
/// <summary>
///
/// </summary>
/// <returns></returns>
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)
};
}
/// <summary>
///
/// </summary>
public override XSigTokenType TokenType
{
get { return XSigTokenType.Analog; }
}
/// <summary>
///
/// </summary>
/// <param name="offset"></param>
/// <returns></returns>
public override XSigToken GetTokenWithOffset(int offset)
{
if (offset == 0) return this;
return new XSigAnalogToken(Index + offset, Value);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
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)
};
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return Index + " = 0x" + Value.ToString("X4");
}
/// <summary>
///
/// </summary>
/// <param name="offset"></param>
/// <returns></returns>
/// <summary>
/// GetTokenWithOffset method
/// </summary>
public override XSigToken GetTokenWithOffset(int offset)
{
if (offset == 0) return this;
return new XSigAnalogToken(Index + offset, Value);
}
/// <summary>
///
/// </summary>
/// <param name="format"></param>
/// <param name="formatProvider"></param>
/// <returns></returns>
public string ToString(string format, IFormatProvider formatProvider)
{
return Value.ToString(format, formatProvider);
/// <summary>
///
/// </summary>
/// <returns></returns>
/// <summary>
/// ToString method
/// </summary>
/// <inheritdoc />
public override string ToString()
{
return Index + " = 0x" + Value.ToString("X4");
}
/// <summary>
///
/// </summary>
/// <param name="format"></param>
/// <param name="formatProvider"></param>
/// <returns></returns>
/// <summary>
/// ToString method
/// </summary>
public string ToString(string format, IFormatProvider formatProvider)
{
return Value.ToString(format, formatProvider);
}
}
}

View File

@@ -1,84 +1,95 @@
using System;
namespace PepperDash.Core.Intersystem.Tokens;
/// <summary>
/// Represents an XSigDigitalToken
/// </summary>
public sealed class XSigDigitalToken : XSigToken
namespace PepperDash.Core.Intersystem.Tokens
{
private readonly bool _value;
/// <summary>
///
/// Represents an XSigDigitalToken
/// </summary>
/// <param name="index"></param>
/// <param name="value"></param>
public XSigDigitalToken(int index, bool value)
: base(index)
public sealed class XSigDigitalToken : XSigToken
{
// 12-bits available for digital encoded data
if (index >= 4096 || index < 0)
throw new ArgumentOutOfRangeException("index");
private readonly bool _value;
_value = value;
}
/// <summary>
///
/// </summary>
/// <param name="index"></param>
/// <param name="value"></param>
public XSigDigitalToken(int index, bool value)
: base(index)
{
// 12-bits available for digital encoded data
if (index >= 4096 || index < 0)
throw new ArgumentOutOfRangeException("index");
/// <summary>
///
/// </summary>
public bool Value
{
get { return _value; }
}
_value = value;
}
/// <summary>
///
/// </summary>
public override XSigTokenType TokenType
{
get { return XSigTokenType.Digital; }
}
/// <summary>
///
/// </summary>
public bool Value
{
get { return _value; }
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override byte[] GetBytes()
{
return new[] {
(byte)(0x80 | (Value ? 0 : 0x20) | ((Index - 1) >> 7)),
(byte)((Index - 1) & 0x7F)
};
}
/// <summary>
///
/// </summary>
public override XSigTokenType TokenType
{
get { return XSigTokenType.Digital; }
}
/// <summary>
///
/// </summary>
/// <param name="offset"></param>
/// <returns></returns>
public override XSigToken GetTokenWithOffset(int offset)
{
if (offset == 0) return this;
return new XSigDigitalToken(Index + offset, Value);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override byte[] GetBytes()
{
return new[] {
(byte)(0x80 | (Value ? 0 : 0x20) | ((Index - 1) >> 7)),
(byte)((Index - 1) & 0x7F)
};
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return Index + " = " + (Value ? "High" : "Low");
}
/// <summary>
///
/// </summary>
/// <param name="offset"></param>
/// <returns></returns>
/// <summary>
/// GetTokenWithOffset method
/// </summary>
public override XSigToken GetTokenWithOffset(int offset)
{
if (offset == 0) return this;
return new XSigDigitalToken(Index + offset, Value);
}
/// <summary>
///
/// </summary>
/// <param name="formatProvider"></param>
/// <returns></returns>
public string ToString(IFormatProvider formatProvider)
{
return Value.ToString(formatProvider);
/// <summary>
///
/// </summary>
/// <returns></returns>
/// <summary>
/// ToString method
/// </summary>
/// <inheritdoc />
public override string ToString()
{
return Index + " = " + (Value ? "High" : "Low");
}
/// <summary>
///
/// </summary>
/// <param name="formatProvider"></param>
/// <returns></returns>
/// <summary>
/// ToString method
/// </summary>
public string ToString(IFormatProvider formatProvider)
{
return Value.ToString(formatProvider);
}
}
}

View File

@@ -1,80 +1,88 @@
using System;
using System.Text;
namespace PepperDash.Core.Intersystem.Tokens;
/// <summary>
/// Represents an XSigSerialToken
/// </summary>
public sealed class XSigSerialToken : XSigToken
namespace PepperDash.Core.Intersystem.Tokens
{
private readonly string _value;
/// <summary>
/// Constructor
/// Represents an XSigSerialToken
/// </summary>
/// <param name="index"></param>
/// <param name="value"></param>
public XSigSerialToken(int index, string value)
: base(index)
public sealed class XSigSerialToken : XSigToken
{
// 10-bits available for serial encoded data
if (index >= 1024 || index < 0)
throw new ArgumentOutOfRangeException("index");
private readonly string _value;
_value = value;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="index"></param>
/// <param name="value"></param>
public XSigSerialToken(int index, string value)
: base(index)
{
// 10-bits available for serial encoded data
if (index >= 1024 || index < 0)
throw new ArgumentOutOfRangeException("index");
/// <summary>
///
/// </summary>
public string Value
{
get { return _value; }
}
_value = value;
}
/// <summary>
///
/// </summary>
public override XSigTokenType TokenType
{
get { return XSigTokenType.Serial; }
}
/// <summary>
///
/// </summary>
public string Value
{
get { return _value; }
}
/// <summary>
///
/// </summary>
/// <returns></returns>
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;
/// <summary>
///
/// </summary>
public override XSigTokenType TokenType
{
get { return XSigTokenType.Serial; }
}
Buffer.BlockCopy(serialBytes, 0, xsig, 2, serialBytes.Length);
return xsig;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
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;
/// <summary>
///
/// </summary>
/// <param name="offset"></param>
/// <returns></returns>
public override XSigToken GetTokenWithOffset(int offset)
{
if (offset == 0) return this;
return new XSigSerialToken(Index + offset, Value);
}
Buffer.BlockCopy(serialBytes, 0, xsig, 2, serialBytes.Length);
return xsig;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return Index + " = \"" + Value + "\"";
/// <summary>
///
/// </summary>
/// <param name="offset"></param>
/// <returns></returns>
/// <summary>
/// GetTokenWithOffset method
/// </summary>
public override XSigToken GetTokenWithOffset(int offset)
{
if (offset == 0) return this;
return new XSigSerialToken(Index + offset, Value);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
/// <summary>
/// ToString method
/// </summary>
/// <inheritdoc />
public override string ToString()
{
return Index + " = \"" + Value + "\"";
}
}
}

View File

@@ -1,44 +1,45 @@
namespace PepperDash.Core.Intersystem.Tokens;
/// <summary>
/// Represents the base class for all XSig datatypes.
/// </summary>
public abstract class XSigToken
namespace PepperDash.Core.Intersystem.Tokens
{
private readonly int _index;
/// <summary>
/// Constructs an XSigToken with the specified index.
/// Represents the base class for all XSig datatypes.
/// </summary>
/// <param name="index">Index for the data.</param>
protected XSigToken(int index)
public abstract class XSigToken
{
_index = index;
private readonly int _index;
/// <summary>
/// Constructs an XSigToken with the specified index.
/// </summary>
/// <param name="index">Index for the data.</param>
protected XSigToken(int index)
{
_index = index;
}
/// <summary>
/// XSig 1-based index.
/// </summary>
public int Index
{
get { return _index; }
}
/// <summary>
/// XSigToken type.
/// </summary>
public abstract XSigTokenType TokenType { get; }
/// <summary>
/// Generates the XSig bytes for the corresponding token.
/// </summary>
/// <returns>XSig byte array.</returns>
public abstract byte[] GetBytes();
/// <summary>
/// Returns a new token if necessary with an updated index based on the specified offset.
/// </summary>
/// <param name="offset">Offset to adjust the index with.</param>
/// <returns>XSigToken</returns>
public abstract XSigToken GetTokenWithOffset(int offset);
}
/// <summary>
/// XSig 1-based index.
/// </summary>
public int Index
{
get { return _index; }
}
/// <summary>
/// XSigToken type.
/// </summary>
public abstract XSigTokenType TokenType { get; }
/// <summary>
/// Generates the XSig bytes for the corresponding token.
/// </summary>
/// <returns>XSig byte array.</returns>
public abstract byte[] GetBytes();
/// <summary>
/// Returns a new token if necessary with an updated index based on the specified offset.
/// </summary>
/// <param name="offset">Offset to adjust the index with.</param>
/// <returns>XSigToken</returns>
public abstract XSigToken GetTokenWithOffset(int offset);
}

View File

@@ -1,22 +1,23 @@
namespace PepperDash.Core.Intersystem.Tokens;
/// <summary>
/// XSig token types.
/// </summary>
public enum XSigTokenType
namespace PepperDash.Core.Intersystem.Tokens
{
/// <summary>
/// Digital signal datatype.
/// XSig token types.
/// </summary>
Digital,
public enum XSigTokenType
{
/// <summary>
/// Digital signal datatype.
/// </summary>
Digital,
/// <summary>
/// Analog signal datatype.
/// </summary>
Analog,
/// <summary>
/// Analog signal datatype.
/// </summary>
Analog,
/// <summary>
/// Serial signal datatype.
/// </summary>
Serial
/// <summary>
/// Serial signal datatype.
/// </summary>
Serial
}
}

View File

@@ -18,221 +18,264 @@ using PepperDash.Core.Intersystem.Tokens;
11111111 <- denotes end of data
*/
namespace PepperDash.Core.Intersystem;
/// <summary>
/// Helper methods for creating XSig byte sequences compatible with the Intersystem Communications (ISC) symbol.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public static class XSigHelpers
namespace PepperDash.Core.Intersystem
{
/// <summary>
/// Forces all outputs to 0.
/// Helper methods for creating XSig byte sequences compatible with the Intersystem Communications (ISC) symbol.
/// </summary>
/// <returns>Bytes in XSig format for clear outputs trigger.</returns>
public static byte[] ClearOutputs()
/// <remarks>
/// 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.
/// </remarks>
public static class XSigHelpers
{
return new byte[] { 0xFC };
}
/// <summary>
/// Evaluate all inputs and re-transmit any digital, analog, and permanent serail signals not set to 0.
/// </summary>
/// <returns>Bytes in XSig format for send status trigger.</returns>
public static byte[] SendStatus()
{
return new byte[] { 0xFD };
}
/// <summary>
/// Get bytes for an IXSigStateResolver object.
/// </summary>
/// <param name="xSigSerialization">XSig state resolver.</param>
/// <returns>Bytes in XSig format for each token within the state representation.</returns>
public static byte[] GetBytes(IXSigSerialization xSigSerialization)
{
return GetBytes(xSigSerialization, 0);
}
/// <summary>
/// Get bytes for an IXSigStateResolver object, with a specified offset.
/// </summary>
/// <param name="xSigSerialization">XSig state resolver.</param>
/// <param name="offset">Offset to which the data will be aligned.</param>
/// <returns>Bytes in XSig format for each token within the state representation.</returns>
public static byte[] GetBytes(IXSigSerialization xSigSerialization, int offset)
{
var tokens = xSigSerialization.Serialize();
if (tokens == null) return new byte[0];
using (var memoryStream = new MemoryStream())
/// <summary>
/// Forces all outputs to 0.
/// </summary>
/// <returns>Bytes in XSig format for clear outputs trigger.</returns>
public static byte[] ClearOutputs()
{
using (var tokenWriter = new XSigTokenStreamWriter(memoryStream))
tokenWriter.WriteXSigData(xSigSerialization, offset);
return memoryStream.ToArray();
}
}
/// <summary>
/// Get bytes for a single digital signal.
/// </summary>
/// <param name="index">1-based digital index</param>
/// <param name="value">Digital data to be encoded</param>
/// <returns>Bytes in XSig format for digtial information.</returns>
public static byte[] GetBytes(int index, bool value)
{
return GetBytes(index, 0, value);
}
/// <summary>
/// Get bytes for a single digital signal.
/// </summary>
/// <param name="index">1-based digital index</param>
/// <param name="offset">Index offset.</param>
/// <param name="value">Digital data to be encoded</param>
/// <returns>Bytes in XSig format for digtial information.</returns>
public static byte[] GetBytes(int index, int offset, bool value)
{
return new XSigDigitalToken(index + offset, value).GetBytes();
}
/// <summary>
/// Get byte sequence for multiple digital signals.
/// </summary>
/// <param name="startIndex">Starting index of the sequence.</param>
/// <param name="values">Digital signal value array.</param>
/// <returns>Byte sequence in XSig format for digital signal information.</returns>
public static byte[] GetBytes(int startIndex, bool[] values)
{
return GetBytes(startIndex, 0, values);
}
/// <summary>
/// Get byte sequence for multiple digital signals.
/// </summary>
/// <param name="startIndex">Starting index of the sequence.</param>
/// <param name="offset">Index offset.</param>
/// <param name="values">Digital signal value array.</param>
/// <returns>Byte sequence in XSig format for digital signal information.</returns>
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;
}
/// <summary>
/// Get bytes for a single analog signal.
/// </summary>
/// <param name="index">1-based analog index</param>
/// <param name="value">Analog data to be encoded</param>
/// <returns>Bytes in XSig format for analog signal information.</returns>
public static byte[] GetBytes(int index, ushort value)
{
return GetBytes(index, 0, value);
}
/// <summary>
/// Get bytes for a single analog signal.
/// </summary>
/// <param name="index">1-based analog index</param>
/// <param name="offset">Index offset.</param>
/// <param name="value">Analog data to be encoded</param>
/// <returns>Bytes in XSig format for analog signal information.</returns>
public static byte[] GetBytes(int index, int offset, ushort value)
{
return new XSigAnalogToken(index + offset, value).GetBytes();
}
/// <summary>
/// Get byte sequence for multiple analog signals.
/// </summary>
/// <param name="startIndex">Starting index of the sequence.</param>
/// <param name="values">Analog signal value array.</param>
/// <returns>Byte sequence in XSig format for analog signal information.</returns>
public static byte[] GetBytes(int startIndex, ushort[] values)
{
return GetBytes(startIndex, 0, values);
}
/// <summary>
/// Get byte sequence for multiple analog signals.
/// </summary>
/// <param name="startIndex">Starting index of the sequence.</param>
/// <param name="offset">Index offset.</param>
/// <param name="values">Analog signal value array.</param>
/// <returns>Byte sequence in XSig format for analog signal information.</returns>
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;
}
/// <summary>
/// Get bytes for a single serial signal.
/// </summary>
/// <param name="index">1-based serial index</param>
/// <param name="value">Serial data to be encoded</param>
/// <returns>Bytes in XSig format for serial signal information.</returns>
public static byte[] GetBytes(int index, string value)
{
return GetBytes(index, 0, value);
}
/// <summary>
/// Get bytes for a single serial signal.
/// </summary>
/// <param name="index">1-based serial index</param>
/// <param name="offset">Index offset.</param>
/// <param name="value">Serial data to be encoded</param>
/// <returns>Bytes in XSig format for serial signal information.</returns>
public static byte[] GetBytes(int index, int offset, string value)
{
return new XSigSerialToken(index + offset, value).GetBytes();
}
/// <summary>
/// Get byte sequence for multiple serial signals.
/// </summary>
/// <param name="startIndex">Starting index of the sequence.</param>
/// <param name="values">Serial signal value array.</param>
/// <returns>Byte sequence in XSig format for serial signal information.</returns>
public static byte[] GetBytes(int startIndex, string[] values)
{
return GetBytes(startIndex, 0, values);
}
/// <summary>
/// Get byte sequence for multiple serial signals.
/// </summary>
/// <param name="startIndex">Starting index of the sequence.</param>
/// <param name="offset">Index offset.</param>
/// <param name="values">Serial signal value array.</param>
/// <returns>Byte sequence in XSig format for serial signal information.</returns>
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 new byte[] { 0xFC };
}
return bytes;
/// <summary>
/// Evaluate all inputs and re-transmit any digital, analog, and permanent serail signals not set to 0.
/// </summary>
/// <returns>Bytes in XSig format for send status trigger.</returns>
public static byte[] SendStatus()
{
return new byte[] { 0xFD };
}
/// <summary>
/// Get bytes for an IXSigStateResolver object.
/// </summary>
/// <param name="xSigSerialization">XSig state resolver.</param>
/// <returns>Bytes in XSig format for each token within the state representation.</returns>
/// <summary>
/// GetBytes method
/// </summary>
public static byte[] GetBytes(IXSigSerialization xSigSerialization)
{
return GetBytes(xSigSerialization, 0);
}
/// <summary>
/// Get bytes for an IXSigStateResolver object, with a specified offset.
/// </summary>
/// <param name="xSigSerialization">XSig state resolver.</param>
/// <param name="offset">Offset to which the data will be aligned.</param>
/// <returns>Bytes in XSig format for each token within the state representation.</returns>
/// <summary>
/// GetBytes method
/// </summary>
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();
}
}
/// <summary>
/// Get bytes for a single digital signal.
/// </summary>
/// <param name="index">1-based digital index</param>
/// <param name="value">Digital data to be encoded</param>
/// <returns>Bytes in XSig format for digtial information.</returns>
/// <summary>
/// GetBytes method
/// </summary>
public static byte[] GetBytes(int index, bool value)
{
return GetBytes(index, 0, value);
}
/// <summary>
/// Get bytes for a single digital signal.
/// </summary>
/// <param name="index">1-based digital index</param>
/// <param name="offset">Index offset.</param>
/// <param name="value">Digital data to be encoded</param>
/// <returns>Bytes in XSig format for digtial information.</returns>
/// <summary>
/// GetBytes method
/// </summary>
public static byte[] GetBytes(int index, int offset, bool value)
{
return new XSigDigitalToken(index + offset, value).GetBytes();
}
/// <summary>
/// Get byte sequence for multiple digital signals.
/// </summary>
/// <param name="startIndex">Starting index of the sequence.</param>
/// <param name="values">Digital signal value array.</param>
/// <returns>Byte sequence in XSig format for digital signal information.</returns>
/// <summary>
/// GetBytes method
/// </summary>
public static byte[] GetBytes(int startIndex, bool[] values)
{
return GetBytes(startIndex, 0, values);
}
/// <summary>
/// Get byte sequence for multiple digital signals.
/// </summary>
/// <param name="startIndex">Starting index of the sequence.</param>
/// <param name="offset">Index offset.</param>
/// <param name="values">Digital signal value array.</param>
/// <returns>Byte sequence in XSig format for digital signal information.</returns>
/// <summary>
/// GetBytes method
/// </summary>
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;
}
/// <summary>
/// Get bytes for a single analog signal.
/// </summary>
/// <param name="index">1-based analog index</param>
/// <param name="value">Analog data to be encoded</param>
/// <returns>Bytes in XSig format for analog signal information.</returns>
/// <summary>
/// GetBytes method
/// </summary>
public static byte[] GetBytes(int index, ushort value)
{
return GetBytes(index, 0, value);
}
/// <summary>
/// Get bytes for a single analog signal.
/// </summary>
/// <param name="index">1-based analog index</param>
/// <param name="offset">Index offset.</param>
/// <param name="value">Analog data to be encoded</param>
/// <returns>Bytes in XSig format for analog signal information.</returns>
/// <summary>
/// GetBytes method
/// </summary>
public static byte[] GetBytes(int index, int offset, ushort value)
{
return new XSigAnalogToken(index + offset, value).GetBytes();
}
/// <summary>
/// Get byte sequence for multiple analog signals.
/// </summary>
/// <param name="startIndex">Starting index of the sequence.</param>
/// <param name="values">Analog signal value array.</param>
/// <returns>Byte sequence in XSig format for analog signal information.</returns>
/// <summary>
/// GetBytes method
/// </summary>
public static byte[] GetBytes(int startIndex, ushort[] values)
{
return GetBytes(startIndex, 0, values);
}
/// <summary>
/// Get byte sequence for multiple analog signals.
/// </summary>
/// <param name="startIndex">Starting index of the sequence.</param>
/// <param name="offset">Index offset.</param>
/// <param name="values">Analog signal value array.</param>
/// <returns>Byte sequence in XSig format for analog signal information.</returns>
/// <summary>
/// GetBytes method
/// </summary>
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;
}
/// <summary>
/// Get bytes for a single serial signal.
/// </summary>
/// <param name="index">1-based serial index</param>
/// <param name="value">Serial data to be encoded</param>
/// <returns>Bytes in XSig format for serial signal information.</returns>
/// <summary>
/// GetBytes method
/// </summary>
public static byte[] GetBytes(int index, string value)
{
return GetBytes(index, 0, value);
}
/// <summary>
/// Get bytes for a single serial signal.
/// </summary>
/// <param name="index">1-based serial index</param>
/// <param name="offset">Index offset.</param>
/// <param name="value">Serial data to be encoded</param>
/// <returns>Bytes in XSig format for serial signal information.</returns>
/// <summary>
/// GetBytes method
/// </summary>
public static byte[] GetBytes(int index, int offset, string value)
{
return new XSigSerialToken(index + offset, value).GetBytes();
}
/// <summary>
/// Get byte sequence for multiple serial signals.
/// </summary>
/// <param name="startIndex">Starting index of the sequence.</param>
/// <param name="values">Serial signal value array.</param>
/// <returns>Byte sequence in XSig format for serial signal information.</returns>
/// <summary>
/// GetBytes method
/// </summary>
public static byte[] GetBytes(int startIndex, string[] values)
{
return GetBytes(startIndex, 0, values);
}
/// <summary>
/// Get byte sequence for multiple serial signals.
/// </summary>
/// <param name="startIndex">Starting index of the sequence.</param>
/// <param name="offset">Index offset.</param>
/// <param name="values">Serial signal value array.</param>
/// <returns>Byte sequence in XSig format for serial signal information.</returns>
/// <summary>
/// GetBytes method
/// </summary>
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;
}
}
}

View File

@@ -4,143 +4,153 @@ using Crestron.SimplSharp.CrestronIO;
using PepperDash.Core.Intersystem.Serialization;
using PepperDash.Core.Intersystem.Tokens;
namespace PepperDash.Core.Intersystem;
/// <summary>
/// XSigToken stream reader.
/// </summary>
public sealed class XSigTokenStreamReader : IDisposable
namespace PepperDash.Core.Intersystem
{
private readonly Stream _stream;
private readonly bool _leaveOpen;
/// <inheritdoc />
/// <summary>
/// XSigToken stream reader constructor.
/// XSigToken stream reader.
/// </summary>
/// <param name="stream">Input stream to read from.</param>
/// <exception cref="T:System.ArgumentNullException">Stream is null.</exception>
/// <exception cref="T:System.ArgumentException">Stream cannot be read from.</exception>
public XSigTokenStreamReader(Stream stream)
: this(stream, false) { }
/// <summary>
/// XSigToken stream reader constructor.
/// </summary>
/// <param name="stream">Input stream to read from.</param>
/// <param name="leaveOpen">Determines whether to leave the stream open or not.</param>
/// <exception cref="ArgumentNullException">Stream is null.</exception>
/// <exception cref="ArgumentException">Stream cannot be read from.</exception>
public XSigTokenStreamReader(Stream stream, bool leaveOpen)
public sealed class XSigTokenStreamReader : IDisposable
{
if (stream == null)
throw new ArgumentNullException("stream");
if (!stream.CanRead)
throw new ArgumentException("The specified stream cannot be read from.");
private readonly Stream _stream;
private readonly bool _leaveOpen;
_stream = stream;
_leaveOpen = leaveOpen;
}
/// <inheritdoc />
/// <summary>
/// XSigToken stream reader constructor.
/// </summary>
/// <param name="stream">Input stream to read from.</param>
/// <exception cref="T:System.ArgumentNullException">Stream is null.</exception>
/// <exception cref="T:System.ArgumentException">Stream cannot be read from.</exception>
public XSigTokenStreamReader(Stream stream)
: this(stream, false) { }
/// <summary>
/// Reads a 16-bit unsigned integer from the specified stream using Big Endian byte order.
/// </summary>
/// <param name="stream">Input stream</param>
/// <param name="value">Result</param>
/// <returns>True if successful, otherwise false.</returns>
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;
}
/// <summary>
/// Read XSig token from the stream.
/// </summary>
/// <returns>XSigToken</returns>
/// <exception cref="ArgumentOutOfRangeException">Offset is less than 0.</exception>
public XSigToken ReadXSigToken()
{
ushort prefix;
if (!TryReadUInt16BE(_stream, out prefix))
return null;
if ((prefix & 0xF880) == 0xC800) // Serial data
/// <summary>
/// XSigToken stream reader constructor.
/// </summary>
/// <param name="stream">Input stream to read from.</param>
/// <param name="leaveOpen">Determines whether to leave the stream open or not.</param>
/// <exception cref="ArgumentNullException">Stream is null.</exception>
/// <exception cref="ArgumentException">Stream cannot be read from.</exception>
public XSigTokenStreamReader(Stream stream, bool leaveOpen)
{
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;
}
if (stream == null)
throw new ArgumentNullException("stream");
if (!stream.CanRead)
throw new ArgumentException("The specified stream cannot be read from.");
return new XSigSerialToken((ushort)(index + 1), new string(chars, 0, n));
_stream = stream;
_leaveOpen = leaveOpen;
}
if ((prefix & 0xC880) == 0xC000) // Analog data
/// <summary>
/// Reads a 16-bit unsigned integer from the specified stream using Big Endian byte order.
/// </summary>
/// <param name="stream">Input stream</param>
/// <param name="value">Result</param>
/// <returns>True if successful, otherwise false.</returns>
/// <summary>
/// TryReadUInt16BE method
/// </summary>
public static bool TryReadUInt16BE(Stream stream, out ushort value)
{
ushort data;
if (!TryReadUInt16BE(_stream, out 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;
}
/// <summary>
/// Read XSig token from the stream.
/// </summary>
/// <returns>XSigToken</returns>
/// <exception cref="ArgumentOutOfRangeException">Offset is less than 0.</exception>
/// <summary>
/// ReadXSigToken method
/// </summary>
public XSigToken ReadXSigToken()
{
ushort prefix;
if (!TryReadUInt16BE(_stream, out prefix))
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 & 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;
}
if ((prefix & 0xC080) == 0x8000) // Digital data
/// <summary>
/// Reads all available XSig tokens from the stream.
/// </summary>
/// <returns>XSigToken collection.</returns>
/// <summary>
/// ReadAllXSigTokens method
/// </summary>
public IEnumerable<XSigToken> ReadAllXSigTokens()
{
var index = ((prefix & 0x1F00) >> 1) | (prefix & 0x7F);
var value = (prefix & 0x2000) == 0;
return new XSigDigitalToken((ushort)(index + 1), value);
var tokens = new List<XSigToken>();
XSigToken token;
while ((token = ReadXSigToken()) != null)
tokens.Add(token);
return tokens;
}
return null;
}
/// <summary>
/// Attempts to deserialize all XSig data within the stream from the current position.
/// </summary>
/// <typeparam name="T">Type to deserialize the information to.</typeparam>
/// <returns>Deserialized object.</returns>
public T DeserializeStream<T>()
where T : class, IXSigSerialization, new()
{
return new T().Deserialize<T>(ReadAllXSigTokens());
}
/// <summary>
/// Reads all available XSig tokens from the stream.
/// </summary>
/// <returns>XSigToken collection.</returns>
public IEnumerable<XSigToken> ReadAllXSigTokens()
{
var tokens = new List<XSigToken>();
XSigToken token;
while ((token = ReadXSigToken()) != null)
tokens.Add(token);
return tokens;
}
/// <summary>
/// Attempts to deserialize all XSig data within the stream from the current position.
/// </summary>
/// <typeparam name="T">Type to deserialize the information to.</typeparam>
/// <returns>Deserialized object.</returns>
public T DeserializeStream<T>()
where T : class, IXSigSerialization, new()
{
return new T().Deserialize<T>(ReadAllXSigTokens());
}
/// <summary>
/// Disposes of the internal stream if specified to not leave open.
/// </summary>
public void Dispose()
{
if (!_leaveOpen)
_stream.Dispose();
/// <summary>
/// Disposes of the internal stream if specified to not leave open.
/// </summary>
public void Dispose()
{
if (!_leaveOpen)
_stream.Dispose();
}
}
}

View File

@@ -5,131 +5,147 @@ using Crestron.SimplSharp.CrestronIO;
using PepperDash.Core.Intersystem.Serialization;
using PepperDash.Core.Intersystem.Tokens;
namespace PepperDash.Core.Intersystem;
/// <summary>
/// XSigToken stream writer.
/// </summary>
public sealed class XSigTokenStreamWriter : IDisposable
namespace PepperDash.Core.Intersystem
{
private readonly Stream _stream;
private readonly bool _leaveOpen;
/// <inheritdoc />
/// <summary>
/// XSigToken stream writer constructor.
/// XSigToken stream writer.
/// </summary>
/// <param name="stream">Input stream to write to.</param>
/// <exception cref="T:System.ArgumentNullException">Stream is null.</exception>
/// <exception cref="T:System.ArgumentException">Stream cannot be written to.</exception>
public XSigTokenStreamWriter(Stream stream)
: this(stream, false) { }
/// <summary>
/// XSigToken stream writer constructor.
/// </summary>
/// <param name="stream">Input stream to write to.</param>
/// <param name="leaveOpen">Determines whether to leave the stream open or not.</param>
/// <exception cref="ArgumentNullException">Stream is null.</exception>
/// <exception cref="ArgumentException">Stream cannot be written to.</exception>
public XSigTokenStreamWriter(Stream stream, bool leaveOpen)
public sealed class XSigTokenStreamWriter : IDisposable
{
if (stream == null)
throw new ArgumentNullException("stream");
if (!stream.CanWrite)
throw new ArgumentException("The specified stream cannot be written to.");
private readonly Stream _stream;
private readonly bool _leaveOpen;
_stream = stream;
_leaveOpen = leaveOpen;
}
/// <inheritdoc />
/// <summary>
/// XSigToken stream writer constructor.
/// </summary>
/// <param name="stream">Input stream to write to.</param>
/// <exception cref="T:System.ArgumentNullException">Stream is null.</exception>
/// <exception cref="T:System.ArgumentException">Stream cannot be written to.</exception>
public XSigTokenStreamWriter(Stream stream)
: this(stream, false) { }
/// <summary>
/// Write XSig data gathered from an IXSigStateResolver to the stream.
/// </summary>
/// <param name="xSigSerialization">IXSigStateResolver object.</param>
public void WriteXSigData(IXSigSerialization xSigSerialization)
{
WriteXSigData(xSigSerialization, 0);
}
/// <summary>
/// Write XSig data gathered from an IXSigStateResolver to the stream.
/// </summary>
/// <param name="xSigSerialization">IXSigStateResolver object.</param>
/// <param name="offset">Index offset for each XSigToken.</param>
public void WriteXSigData(IXSigSerialization xSigSerialization, int offset)
{
if (xSigSerialization == null)
throw new ArgumentNullException("xSigSerialization");
var tokens = xSigSerialization.Serialize();
WriteXSigData(tokens, offset);
}
/// <summary>
/// Write XSigToken to the stream.
/// </summary>
/// <param name="token">XSigToken object.</param>
public void WriteXSigData(XSigToken token)
{
WriteXSigData(token, 0);
}
/// <summary>
/// Write XSigToken to the stream.
/// </summary>
/// <param name="token">XSigToken object.</param>
/// <param name="offset">Index offset for each XSigToken.</param>
public void WriteXSigData(XSigToken token, int offset)
{
WriteXSigData(new[] { token }, offset);
}
/// <summary>
/// Writes an array of XSigTokens to the stream.
/// </summary>
/// <param name="tokens">XSigToken objects.</param>
public void WriteXSigData(XSigToken[] tokens)
{
WriteXSigData(tokens.AsEnumerable());
}
/// <summary>
/// Write an enumerable collection of XSigTokens to the stream.
/// </summary>
/// <param name="tokens">XSigToken objects.</param>
public void WriteXSigData(IEnumerable<XSigToken> tokens)
{
WriteXSigData(tokens, 0);
}
/// <summary>
/// Write an enumerable collection of XSigTokens to the stream.
/// </summary>
/// <param name="tokens">XSigToken objects.</param>
/// <param name="offset">Index offset for each XSigToken.</param>
public void WriteXSigData(IEnumerable<XSigToken> tokens, int offset)
{
if (offset < 0)
throw new ArgumentOutOfRangeException("offset", "Offset must be greater than or equal to 0.");
if (tokens != null)
/// <summary>
/// XSigToken stream writer constructor.
/// </summary>
/// <param name="stream">Input stream to write to.</param>
/// <param name="leaveOpen">Determines whether to leave the stream open or not.</param>
/// <exception cref="ArgumentNullException">Stream is null.</exception>
/// <exception cref="ArgumentException">Stream cannot be written to.</exception>
public XSigTokenStreamWriter(Stream stream, bool leaveOpen)
{
foreach (var token in tokens)
if (stream == null)
throw new ArgumentNullException("stream");
if (!stream.CanWrite)
throw new ArgumentException("The specified stream cannot be written to.");
_stream = stream;
_leaveOpen = leaveOpen;
}
/// <summary>
/// Write XSig data gathered from an IXSigStateResolver to the stream.
/// </summary>
/// <param name="xSigSerialization">IXSigStateResolver object.</param>
/// <summary>
/// WriteXSigData method
/// </summary>
public void WriteXSigData(IXSigSerialization xSigSerialization)
{
WriteXSigData(xSigSerialization, 0);
}
/// <summary>
/// Write XSig data gathered from an IXSigStateResolver to the stream.
/// </summary>
/// <param name="xSigSerialization">IXSigStateResolver object.</param>
/// <param name="offset">Index offset for each XSigToken.</param>
/// <summary>
/// WriteXSigData method
/// </summary>
public void WriteXSigData(IXSigSerialization xSigSerialization, int offset)
{
if (xSigSerialization == null)
throw new ArgumentNullException("xSigSerialization");
var tokens = xSigSerialization.Serialize();
WriteXSigData(tokens, offset);
}
/// <summary>
/// Write XSigToken to the stream.
/// </summary>
/// <param name="token">XSigToken object.</param>
/// <summary>
/// WriteXSigData method
/// </summary>
public void WriteXSigData(XSigToken token)
{
WriteXSigData(token, 0);
}
/// <summary>
/// Write XSigToken to the stream.
/// </summary>
/// <param name="token">XSigToken object.</param>
/// <param name="offset">Index offset for each XSigToken.</param>
/// <summary>
/// WriteXSigData method
/// </summary>
public void WriteXSigData(XSigToken token, int offset)
{
WriteXSigData(new[] { token }, offset);
}
/// <summary>
/// Writes an array of XSigTokens to the stream.
/// </summary>
/// <param name="tokens">XSigToken objects.</param>
public void WriteXSigData(XSigToken[] tokens)
{
WriteXSigData(tokens.AsEnumerable());
}
/// <summary>
/// Write an enumerable collection of XSigTokens to the stream.
/// </summary>
/// <param name="tokens">XSigToken objects.</param>
public void WriteXSigData(IEnumerable<XSigToken> tokens)
{
WriteXSigData(tokens, 0);
}
/// <summary>
/// Write an enumerable collection of XSigTokens to the stream.
/// </summary>
/// <param name="tokens">XSigToken objects.</param>
/// <param name="offset">Index offset for each XSigToken.</param>
/// <summary>
/// WriteXSigData method
/// </summary>
public void WriteXSigData(IEnumerable<XSigToken> tokens, int offset)
{
if (offset < 0)
throw new ArgumentOutOfRangeException("offset", "Offset must be greater than or equal to 0.");
if (tokens != null)
{
if (token == null) continue;
var bytes = token.GetTokenWithOffset(offset).GetBytes();
_stream.Write(bytes, 0, bytes.Length);
foreach (var token in tokens)
{
if (token == null) continue;
var bytes = token.GetTokenWithOffset(offset).GetBytes();
_stream.Write(bytes, 0, bytes.Length);
}
}
}
}
/// <summary>
/// Disposes of the internal stream if specified to not leave open.
/// </summary>
public void Dispose()
{
if (!_leaveOpen)
_stream.Dispose();
/// <summary>
/// Dispose method
/// </summary>
public void Dispose()
{
if (!_leaveOpen)
_stream.Dispose();
}
}
}

View File

@@ -3,421 +3,517 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using System.Reflection;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.EthernetCommunication;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core.Config;
using Serilog.Events;
//using PepperDash.Essentials.Devices.Common.Cameras;
namespace PepperDash.Essentials.Core.Bridges;
/// <summary>
/// Base class for bridge API variants
/// </summary>
public abstract class BridgeApi : EssentialsDevice
namespace PepperDash.Essentials.Core.Bridges
{
protected BridgeApi(string key) :
base(key)
/// <summary>
/// Base class for bridge API variants
/// </summary>
[Obsolete("Will be removed in v3.0.0")]
public abstract class BridgeApi : EssentialsDevice
{
}
}
/// <summary>
/// Bridge API using EISC
/// </summary>
public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor
{
public EiscApiPropertiesConfig PropertiesConfig { get; private set; }
public Dictionary<string, JoinMapBaseAdvanced> JoinMaps { get; private set; }
public BasicTriList Eisc { get; private set; }
public EiscApiAdvanced(DeviceConfig dc, BasicTriList eisc) :
base(dc.Key)
{
JoinMaps = new Dictionary<string, JoinMapBaseAdvanced>();
PropertiesConfig = dc.Properties.ToObject<EiscApiPropertiesConfig>();
//PropertiesConfig = JsonConvert.DeserializeObject<EiscApiPropertiesConfig>(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)
/// <summary>
/// Constructor
/// </summary>
/// <param name="key">Device key</param>
protected BridgeApi(string key) :
base(key)
{
Debug.LogMessage(LogEventLevel.Debug, this, "No devices linked to this bridge");
return;
}
}
/// <summary>
/// Class to link devices and rooms to an EISC Instance
/// </summary>
public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor
{
/// <summary>
/// Gets the PropertiesConfig
/// </summary>
public EiscApiPropertiesConfig PropertiesConfig { get; private set; }
/// <summary>
/// Gets the JoinMaps dictionary
/// </summary>
public Dictionary<string, JoinMapBaseAdvanced> JoinMaps { get; private set; }
/// <summary>
/// Gets the EISC instance
/// </summary>
public BasicTriList Eisc { get; private set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="dc">Device configuration</param>
/// <param name="eisc">EISC instance</param>
public EiscApiAdvanced(DeviceConfig dc, BasicTriList eisc) :
base(dc.Key)
{
JoinMaps = new Dictionary<string, JoinMapBaseAdvanced>();
PropertiesConfig = dc.Properties.ToObject<EiscApiPropertiesConfig>();
Eisc = eisc;
Eisc.SigChange += Eisc_SigChange;
CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, Eisc, 120000, 300000);
AddPostActivationAction(LinkDevices);
AddPostActivationAction(LinkRooms);
AddPostActivationAction(RegisterEisc);
}
foreach (var d in PropertiesConfig.Devices)
/// <summary>
/// CustomActivate method
/// </summary>
public override bool CustomActivate()
{
var device = DeviceManager.GetDeviceForKey(d.DeviceKey);
CommunicationMonitor.Start();
return base.CustomActivate();
}
if (device == null)
/// <summary>
/// Deactivate method
/// </summary>
public override bool Deactivate()
{
CommunicationMonitor.Stop();
return base.Deactivate();
}
private void LinkDevices()
{
Debug.LogMessage(LogEventLevel.Debug, this, "Linking Devices...");
if (PropertiesConfig.Devices == null)
{
continue;
this.LogDebug("No devices linked to this bridge");
return;
}
Debug.LogMessage(LogEventLevel.Debug, this, "Linking Device: '{0}'", device.Key);
if (device is IBridgeAdvanced bridge)
foreach (var d in PropertiesConfig.Devices)
{
bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this);
continue;
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;
}
Debug.LogMessage(LogEventLevel.Information, this,
"{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.",
device.Key);
}
}
var registerResult = Eisc.Register();
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)
if (registerResult != eDeviceRegistrationUnRegistrationResponse.Success)
{
Debug.LogMessage(LogEventLevel.Debug, this,
"Room {0} does not implement IBridgeAdvanced. Skipping...", room.RoomKey);
continue;
this.LogVerbose("Registration result: {registerResult}", registerResult);
return;
}
rm.LinkToApi(Eisc, room.JoinStart, room.JoinMapKey, this);
}
}
/// <summary>
/// Adds a join map
/// </summary>
/// <param name="deviceKey"></param>
/// <param name="joinMap"></param>
public void AddJoinMap(string deviceKey, JoinMapBaseAdvanced joinMap)
{
if (!JoinMaps.ContainsKey(deviceKey))
{
JoinMaps.Add(deviceKey, joinMap);
}
else
{
Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to add join map with key '{0}'. Key already exists in JoinMaps dictionary", deviceKey);
}
}
/// <summary>
/// Prints all the join maps on this bridge
/// </summary>
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();
}
}
/// <summary>
/// Generates markdown for all join maps on this bridge
/// </summary>
public virtual void MarkdownForBridge(string bridgeKey)
{
Debug.LogMessage(LogEventLevel.Information, this, "Writing Joinmaps to files for EISC IPID: {0}", Eisc.ID.ToString("X"));
foreach (var joinMap in JoinMaps)
{
Debug.LogMessage(LogEventLevel.Information, "Generating markdown for device '{0}':", joinMap.Key);
joinMap.Value.MarkdownJoinMapInfo(joinMap.Key, bridgeKey);
}
}
/// <summary>
/// Prints the join map for a device by key
/// </summary>
/// <param name="deviceKey"></param>
public void PrintJoinMapForDevice(string deviceKey)
{
var joinMap = JoinMaps[deviceKey];
if (joinMap == null)
{
Debug.LogMessage(LogEventLevel.Information, this, "Unable to find joinMap for device with key: '{0}'", deviceKey);
return;
this.LogDebug("EISC registration successful");
}
Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key);
joinMap.PrintJoinMapInfo();
}
/// <summary>
/// Prints the join map for a device by key
/// </summary>
/// <param name="deviceKey"></param>
public void MarkdownJoinMapForDevice(string deviceKey, string bridgeKey)
{
var joinMap = JoinMaps[deviceKey];
if (joinMap == null)
/// <summary>
/// Link rooms to this EISC. Rooms MUST implement IBridgeAdvanced
/// </summary>
public void LinkRooms()
{
Debug.LogMessage(LogEventLevel.Information, this, "Unable to find joinMap for device with key: '{0}'", deviceKey);
return;
}
this.LogDebug("Linking Rooms...");
Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key);
joinMap.MarkdownJoinMapInfo(deviceKey, bridgeKey);
}
/// <summary>
/// Used for debugging to trigger an action based on a join number and type
/// </summary>
/// <param name="join"></param>
/// <param name="type"></param>
/// <param name="state"></param>
public void ExecuteJoinAction(uint join, string type, object state)
{
try
{
switch (type.ToLower())
if (PropertiesConfig.Rooms == null)
{
case "digital":
{
var uo = Eisc.BooleanOutput[join].UserObject as Action<bool>;
if (uo != 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);
}
}
/// <summary>
/// Adds a join map
/// </summary>
/// <param name="deviceKey">The key of the device to add the join map for</param>
/// <param name="joinMap">The join map to add</param>
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);
}
}
/// <summary>
/// PrintJoinMaps method
/// </summary>
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();
}
}
/// <summary>
/// MarkdownForBridge method
/// </summary>
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);
}
}
/// <summary>
/// Prints the join map for a device by key
/// </summary>
/// <param name="deviceKey">The key of the device to print the join map for</param>
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();
}
/// <summary>
/// Prints the join map for a device by key in Markdown format
/// </summary>
/// <param name="deviceKey">The key of the device to print the join map for</param>
/// <param name="bridgeKey">The key of the bridge to use for the Markdown output</param>
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);
}
/// <summary>
/// Used for debugging to trigger an action based on a join number and type
/// </summary>
/// <param name="join">The join number to execute the action for</param>
/// <param name="type">The type of join (digital, analog, serial)</param>
/// <param name="state">The state to pass to the action</param>
public void ExecuteJoinAction(uint join, string type, object state)
{
try
{
switch (type.ToLower())
{
case "digital":
{
Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString());
uo(Convert.ToBoolean(state));
if (Eisc.BooleanOutput[join].UserObject is Action<bool> userObject)
{
this.LogVerbose("Executing Boolean Action");
userObject(Convert.ToBoolean(state));
}
else
this.LogVerbose("User Object is null. Nothing to Execute");
break;
}
else
Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute");
case "analog":
{
if (Eisc.UShortOutput[join].UserObject is Action<ushort> 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<string> 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: ");
}
}
/// <summary>
/// Handle incoming sig changes
/// </summary>
/// <param name="currentDevice">BasicTriList device that triggered the event</param>
/// <param name="args">Event arguments containing the signal information</param>
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<bool>)
{
this.LogDebug("Executing Boolean Action");
(userObject as Action<bool>)(args.Sig.BoolValue);
}
else if (userObject is Action<ushort>)
{
this.LogDebug("Executing Analog Action");
(userObject as Action<ushort>)(args.Sig.UShortValue);
}
else if (userObject is Action<string>)
{
this.LogDebug("Executing Serial Action");
(userObject as Action<string>)(args.Sig.StringValue);
}
}
catch (Exception e)
{
this.LogError("Eisc_SigChange handler error: {message}", e.Message);
this.LogDebug(e, "Stack Trace: ");
}
}
#region Implementation of ICommunicationMonitor
/// <summary>
/// Gets or sets the CommunicationMonitor
/// </summary>
public StatusMonitorBase CommunicationMonitor { get; private set; }
#endregion
}
/// <summary>
/// Represents a EiscApiPropertiesConfig
/// </summary>
public class EiscApiPropertiesConfig
{
/// <summary>
/// Gets or sets the Control
/// </summary>
[JsonProperty("control")]
public EssentialsControlPropertiesConfig Control { get; set; }
/// <summary>
/// Gets or sets the Devices
/// </summary>
[JsonProperty("devices")]
public List<ApiDevicePropertiesConfig> Devices { get; set; }
/// <summary>
/// Gets or sets the Rooms
/// </summary>
[JsonProperty("rooms")]
public List<ApiRoomPropertiesConfig> Rooms { get; set; }
/// <summary>
/// Represents a ApiDevicePropertiesConfig
/// </summary>
public class ApiDevicePropertiesConfig
{
/// <summary>
/// Gets or sets the DeviceKey
/// </summary>
[JsonProperty("deviceKey")]
public string DeviceKey { get; set; }
/// <summary>
/// Gets or sets the JoinStart
/// </summary>
[JsonProperty("joinStart")]
public uint JoinStart { get; set; }
/// <summary>
/// Gets or sets the JoinMapKey
/// </summary>
[JsonProperty("joinMapKey")]
public string JoinMapKey { get; set; }
}
/// <summary>
/// Represents a ApiRoomPropertiesConfig
/// </summary>
public class ApiRoomPropertiesConfig
{
/// <summary>
/// Gets or sets the RoomKey
/// </summary>
[JsonProperty("roomKey")]
public string RoomKey { get; set; }
/// <summary>
/// Gets or sets the JoinStart
/// </summary>
[JsonProperty("joinStart")]
public uint JoinStart { get; set; }
/// <summary>
/// Gets or sets the JoinMapKey
/// </summary>
[JsonProperty("joinMapKey")]
public string JoinMapKey { get; set; }
}
}
/// <summary>
/// Factory class for EiscApiAdvanced devices
/// </summary>
/// <remarks>
/// 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
/// </remarks>
public class EiscApiAdvancedFactory : EssentialsDeviceFactory<EiscApiAdvanced>
{
/// <summary>
/// Constructor
/// </summary>
public EiscApiAdvancedFactory()
{
TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced", "eiscapiadvudp", "eiscapiadvancedudp" };
}
/// <inheritdoc />
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.LogDebug("Attempting to create new EiscApiAdvanced Device");
var controlProperties = CommFactory.GetControlPropertiesConfig(dc);
BasicTriList eisc;
switch (dc.Type.ToLower())
{
case "eiscapiadvudp":
case "eiscapiadvancedudp":
{
eisc = new EthernetIntersystemCommunications(controlProperties.IpIdInt,
controlProperties.TcpSshProperties.Address, Global.ControlSystem);
break;
}
case "analog":
case "eiscapiadv":
case "eiscapiadvanced":
{
var uo = Eisc.BooleanOutput[join].UserObject as Action<ushort>;
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;
eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(controlProperties.IpIdInt,
controlProperties.TcpSshProperties.Address, Global.ControlSystem);
break;
}
case "serial":
case "eiscapiadvancedserver":
{
var uo = Eisc.BooleanOutput[join].UserObject as Action<string>;
if (uo != null)
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.Verbose, this, "Executing Action: {0}", uo.ToString());
uo(Convert.ToString(state));
Debug.LogInformation("Unable to build VC-4 EISC Client for device {deviceKey}. Room ID is missing or empty", dc.Key);
eisc = null;
break;
}
else
Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute");
eisc = new VirtualControlEISCClient(controlProperties.IpIdInt, controlProperties.RoomId,
Global.ControlSystem);
break;
}
default:
{
Debug.LogMessage(LogEventLevel.Verbose, "Unknown join type. Use digital/serial/analog");
break;
}
eisc = null;
break;
}
}
catch (Exception e)
{
Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e);
}
}
if (eisc == null)
{
return null;
}
/// <summary>
/// Handles incoming sig changes
/// </summary>
/// <param name="currentDevice"></param>
/// <param name="args"></param>
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<bool>)
(uo as Action<bool>)(args.Sig.BoolValue);
else if (uo is Action<ushort>)
(uo as Action<ushort>)(args.Sig.UShortValue);
else if (uo is Action<string>)
(uo as Action<string>)(args.Sig.StringValue);
}
catch (Exception e)
{
Debug.LogMessage(LogEventLevel.Verbose, this, "Error in Eisc_SigChange handler: {0}", e);
return new EiscApiAdvanced(dc, eisc);
}
}
#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<ApiDevicePropertiesConfig> Devices { get; set; }
[JsonProperty("rooms")]
public List<ApiRoomPropertiesConfig> 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<EiscApiAdvanced>
{
public EiscApiAdvancedFactory()
{
TypeNames = new List<string> { "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);
}
}

View File

@@ -3,62 +3,67 @@ using Serilog.Events;
//using PepperDash.Essentials.Devices.Common.Cameras;
namespace PepperDash.Essentials.Core.Bridges;
/// <summary>
/// Helper methods for bridges
/// </summary>
public static class BridgeHelper
namespace PepperDash.Essentials.Core.Bridges
{
public static void PrintJoinMap(string command)
/// <summary>
/// Helper methods for bridges
/// </summary>
public static class BridgeHelper
{
var targets = command.Split(' ');
var bridgeKey = targets[0].Trim();
if (!(DeviceManager.GetDeviceForKey(bridgeKey) is EiscApiAdvanced bridge))
public static void PrintJoinMap(string command)
{
Debug.LogMessage(LogEventLevel.Information, "Unable to find advanced bridge with key: '{0}'", bridgeKey);
return;
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();
}
}
if (targets.Length > 1)
/// <summary>
/// JoinmapMarkdown method
/// </summary>
public static void JoinmapMarkdown(string command)
{
var deviceKey = targets[1].Trim();
var targets = command.Split(' ');
if (string.IsNullOrEmpty(deviceKey)) return;
bridge.PrintJoinMapForDevice(deviceKey);
}
else
{
bridge.PrintJoinMaps();
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);
}
}
}
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);
}
}
}

View File

@@ -1,11 +1,19 @@
using Crestron.SimplSharpPro.DeviceSupport;
namespace PepperDash.Essentials.Core.Bridges;
/// <summary>
/// Defines a device that uses JoinMapBaseAdvanced for its join map
/// </summary>
public interface IBridgeAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge);
/// <summary>
/// Defines the contract for IBridgeAdvanced
/// </summary>
public interface IBridgeAdvanced
{
/// <summary>
/// Links the bridge to the API using the provided trilist, join start, join map key, and bridge.
/// </summary>
/// <param name="trilist">The trilist to link to.</param>
/// <param name="joinStart">The starting join number.</param>
/// <param name="joinMapKey">The key for the join map.</param>
/// <param name="bridge">The EISC API bridge.</param>
void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge);
}
}

View File

@@ -1,70 +1,74 @@
using System;
namespace PepperDash.Essentials.Core.Bridges;
public class AirMediaControllerJoinMap : JoinMapBaseAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// Represents a AirMediaControllerJoinMap
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public AirMediaControllerJoinMap(uint joinStart)
: this(joinStart, typeof(AirMediaControllerJoinMap))
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 });
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected AirMediaControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){}
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public AirMediaControllerJoinMap(uint joinStart)
: this(joinStart, typeof(AirMediaControllerJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected AirMediaControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){}
}
}

View File

@@ -1,52 +1,56 @@
using System;
namespace PepperDash.Essentials.Core.Bridges;
public class AppleTvJoinMap : JoinMapBaseAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// Represents a AppleTvJoinMap
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public AppleTvJoinMap(uint joinStart)
: base(joinStart, typeof(AppleTvJoinMap))
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 });
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
public AppleTvJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public AppleTvJoinMap(uint joinStart)
: base(joinStart, typeof(AppleTvJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
public AppleTvJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
}
}
}

View File

@@ -1,44 +1,48 @@
using System;
namespace PepperDash.Essentials.Core.Bridges;
public class C2nRthsControllerJoinMap : JoinMapBaseAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// Represents a C2nRthsControllerJoinMap
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public C2nRthsControllerJoinMap(uint joinStart)
: this(joinStart, typeof(C2nRthsControllerJoinMap))
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 });
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected C2nRthsControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public C2nRthsControllerJoinMap(uint joinStart)
: this(joinStart, typeof(C2nRthsControllerJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected C2nRthsControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
}
}
}

View File

@@ -1,68 +1,69 @@
using System;
namespace PepperDash.Essentials.Core.Bridges;
/// <summary>
/// Join map for CameraBase devices
/// </summary>
public class CameraControllerJoinMap : JoinMapBaseAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// Represents a CameraControllerJoinMap
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public CameraControllerJoinMap(uint joinStart)
: this(joinStart, typeof(CameraControllerJoinMap))
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 });
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected CameraControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){}
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public CameraControllerJoinMap(uint joinStart)
: this(joinStart, typeof(CameraControllerJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected CameraControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){}
}
}

View File

@@ -1,196 +1,201 @@
using System;
namespace PepperDash.Essentials.Core.Bridges;
public class CenOdtOccupancySensorBaseJoinMap : JoinMapBaseAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
#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
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// Represents a CenOdtOccupancySensorBaseJoinMap
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public CenOdtOccupancySensorBaseJoinMap(uint joinStart)
: this(joinStart, typeof(CenOdtOccupancySensorBaseJoinMap))
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
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public CenOdtOccupancySensorBaseJoinMap(uint joinStart)
: this(joinStart, typeof(CenOdtOccupancySensorBaseJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected CenOdtOccupancySensorBaseJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
}
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected CenOdtOccupancySensorBaseJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
}
}

View File

@@ -1,84 +1,88 @@
using System;
namespace PepperDash.Essentials.Core.Bridges;
public class DisplayControllerJoinMap : JoinMapBaseAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// Represents a DisplayControllerJoinMap
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DisplayControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DisplayControllerJoinMap))
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 });
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DisplayControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DisplayControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DisplayControllerJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DisplayControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
}
}
}

View File

@@ -1,73 +1,77 @@
using System;
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 });
namespace PepperDash.Essentials.Core.Bridges {
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// Represents a DmBladeChassisControllerJoinMap
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmBladeChassisControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmBladeChassisControllerJoinMap))
{
}
public class DmBladeChassisControllerJoinMap : JoinMapBaseAdvanced {
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmBladeChassisControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
}
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmBladeChassisControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmBladeChassisControllerJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmBladeChassisControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
}
}
}

View File

@@ -1,169 +1,173 @@
using System;
namespace PepperDash.Essentials.Core.Bridges;
public class DmChassisControllerJoinMap : JoinMapBaseAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
[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},
/// <summary>
/// Represents a DmChassisControllerJoinMap
/// </summary>
public class DmChassisControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("EnableAudioBreakaway")]
public JoinDataComplete EnableAudioBreakaway = new JoinDataComplete(
new JoinData {JoinNumber = 4, JoinSpan = 1},
new JoinMetadata
{
Description = "DM Chassis Video Input Names",
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("InputAudioNames")]
public JoinDataComplete InputAudioNames =
new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 200 },
new JoinMetadata
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmChassisControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmChassisControllerJoinMap))
{
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
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmChassisControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmChassisControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmChassisControllerJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmChassisControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
}
}
}

View File

@@ -1,91 +1,95 @@
using System;
namespace PepperDash.Essentials.Core.Bridges;
public class DmRmcControllerJoinMap : JoinMapBaseAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// Represents a DmRmcControllerJoinMap
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmRmcControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmRmcControllerJoinMap))
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 });
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmRmcControllerJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmRmcControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmRmcControllerJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmRmcControllerJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
}

View File

@@ -1,95 +1,99 @@
using System;
namespace PepperDash.Essentials.Core.Bridges;
public class DmTxControllerJoinMap : JoinMapBaseAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// Represents a DmTxControllerJoinMap
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmTxControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmTxControllerJoinMap))
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 });
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmTxControllerJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmTxControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmTxControllerJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmTxControllerJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
}

View File

@@ -1,173 +1,177 @@
using System;
namespace PepperDash.Essentials.Core.Bridges;
public class DmpsAudioOutputControllerJoinMap : JoinMapBaseAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// Represents a DmpsAudioOutputControllerJoinMap
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmpsAudioOutputControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmpsAudioOutputControllerJoinMap))
public class DmpsAudioOutputControllerJoinMap : JoinMapBaseAdvanced
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmpsAudioOutputControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmpsAudioOutputControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmpsAudioOutputControllerJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmpsAudioOutputControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
}
}
}

View File

@@ -1,49 +1,53 @@
using System;
namespace PepperDash.Essentials.Core.Bridges;
public class DmpsMicrophoneControllerJoinMap : JoinMapBaseAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// Represents a DmpsMicrophoneControllerJoinMap
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmpsMicrophoneControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmpsMicrophoneControllerJoinMap))
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 });
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmpsMicrophoneControllerJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmpsMicrophoneControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmpsMicrophoneControllerJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmpsMicrophoneControllerJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
}

View File

@@ -1,122 +1,126 @@
using System;
namespace PepperDash.Essentials.Core.Bridges;
public class DmpsRoutingControllerJoinMap : JoinMapBaseAdvanced
namespace PepperDash.Essentials.Core.Bridges
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// Represents a DmpsRoutingControllerJoinMap
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmpsRoutingControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmpsRoutingControllerJoinMap))
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 });
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmpsRoutingControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
[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 });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public DmpsRoutingControllerJoinMap(uint joinStart)
: this(joinStart, typeof(DmpsRoutingControllerJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmpsRoutingControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{
}
}
}

View File

@@ -1,7 +1,7 @@
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Core.Bridges.JoinMaps;
namespace PepperDash.Essentials.Core.Bridges.JoinMaps
{
public sealed class GenericIrControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("PLAY")]
@@ -823,4 +823,5 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps;
: base(joinStart, typeof(GenericIrControllerJoinMap))
{
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More