diff --git a/src/PepperDash.Core/PepperDash.Core.csproj b/src/PepperDash.Core/PepperDash.Core.csproj
index daa5c6da..747aefb6 100644
--- a/src/PepperDash.Core/PepperDash.Core.csproj
+++ b/src/PepperDash.Core/PepperDash.Core.csproj
@@ -43,7 +43,7 @@
-
+
diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj
index 251ba316..b7f333bd 100644
--- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj
+++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj
@@ -25,7 +25,7 @@
bin\$(Configuration)\PepperDash_Essentials_Core.xml
-
+
diff --git a/src/PepperDash.Essentials.Core/Touchpanels/Mpc4Touchpanel.cs b/src/PepperDash.Essentials.Core/Touchpanels/Mpc4Touchpanel.cs
new file mode 100644
index 00000000..3d1cb5fc
--- /dev/null
+++ b/src/PepperDash.Essentials.Core/Touchpanels/Mpc4Touchpanel.cs
@@ -0,0 +1,326 @@
+using Crestron.SimplSharpPro;
+using PepperDash.Core;
+using PepperDash.Core.Logging;
+using Serilog.Events;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace PepperDash.Essentials.Core.Touchpanels
+{
+ ///
+ /// A wrapper class for the touchpanel portion of an MPC4 class process to allow for configurable
+ /// behavior of the keypad buttons
+ ///
+ public class Mpc4TouchpanelController : Device
+ {
+ private readonly CrestronControlSystem _processor;
+ private MPC3Basic _touchpanel;
+
+ readonly Dictionary _buttons;
+
+ ///
+ /// Constructor
+ ///
+ /// device key
+ /// device name
+ /// control system processor
+ /// dictionary of keypad buttons
+ public Mpc4TouchpanelController(string key, string name, CrestronControlSystem processor, Dictionary buttons)
+ : base(key, name)
+ {
+ _processor = processor;
+ _buttons = buttons ?? new Dictionary();
+ }
+
+ public override bool CustomActivate()
+ {
+ Debug.LogInformation(this, "Activating MPC4 Touchpanel Controller with key {0}", Key);
+
+ if (_processor.MPC4x102TouchscreenSlot != null)
+ {
+ Debug.LogMessage(LogEventLevel.Information, this, "Using MPC4x102TouchscreenSlot");
+ _touchpanel = _processor.MPC4x102TouchscreenSlot;
+ }
+ else if (_processor.MPC4x201TouchscreenSlot != null)
+ {
+ Debug.LogMessage(LogEventLevel.Information, this, "Using MPC4x201TouchscreenSlot");
+ _touchpanel = _processor.MPC4x201TouchscreenSlot;
+ }
+ else if (_processor.MPC4x301TouchscreenSlot != null)
+ {
+ Debug.LogMessage(LogEventLevel.Information, this, "Using MPC4x301TouchscreenSlot");
+ _touchpanel = _processor.MPC4x301TouchscreenSlot;
+ }
+ else if (_processor.MPC4x302TouchscreenSlot != null)
+ {
+ Debug.LogMessage(LogEventLevel.Information, this, "Using MPC4x302TouchscreenSlot");
+ _touchpanel = _processor.MPC4x302TouchscreenSlot;
+ }
+ else
+ {
+ Debug.LogMessage(LogEventLevel.Error, this, "Failed to find MPC4 Touchpanel Controller with key {0}, check configuration", Key);
+ return false;
+ }
+
+ if (_touchpanel.Registerable)
+ {
+ var registrationResponse = _touchpanel.Register();
+ Debug.LogMessage(LogEventLevel.Information, this, "touchpanel registration response: {0}", registrationResponse);
+ }
+
+ _touchpanel.BaseEvent += Touchpanel_BaseEvent;
+ _touchpanel.ButtonStateChange += Touchpanel_ButtonStateChange;
+ _touchpanel.PanelStateChange += Touchpanel_PanelStateChange;
+
+ foreach (var button in _buttons)
+ {
+ var buttonKey = button.Key.ToLower();
+ var buttonConfig = button.Value;
+
+ InitializeButton(buttonKey, buttonConfig);
+ InitializeButtonFeedback(buttonKey, buttonConfig);
+ }
+
+ ListButtons();
+
+ return _touchpanel.Registered;
+ }
+
+ ///
+ /// Enables/disables buttons based on event type configuration
+ ///
+ ///
+ ///
+ public void InitializeButton(string key, KeypadButton config)
+ {
+ if (config == null)
+ {
+ Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' config is null, unable to initialize", key);
+ return;
+ }
+
+ TryParseInt(key, out int buttonNumber);
+
+ var buttonEventTypes = config.EventTypes;
+ BoolOutputSig enabledFb = null;
+ BoolOutputSig disabledFb = null;
+
+ switch (key)
+ {
+ case ("power"):
+ {
+ if (buttonEventTypes == null || buttonEventTypes.Keys == null)
+ _touchpanel.DisablePowerButton();
+ else
+ _touchpanel.EnablePowerButton();
+
+
+ enabledFb = _touchpanel.PowerButtonEnabledFeedBack;
+ disabledFb = _touchpanel.PowerButtonDisabledFeedBack;
+
+ break;
+ }
+ case ("mute"):
+ {
+ if (buttonEventTypes == null || buttonEventTypes.Keys == null)
+ _touchpanel.DisableMuteButton();
+ else
+ _touchpanel.EnableMuteButton();
+
+
+ enabledFb = _touchpanel.MuteButtonEnabledFeedBack;
+ disabledFb = _touchpanel.MuteButtonDisabledFeedBack;
+
+ break;
+ }
+ default:
+ {
+ if (buttonNumber == 0 || buttonNumber > 9)
+ break;
+
+ if (buttonEventTypes == null || buttonEventTypes.Keys == null)
+ _touchpanel.DisableNumericalButton((uint)buttonNumber);
+ else
+ _touchpanel.EnableNumericalButton((uint)buttonNumber);
+
+
+ if (_touchpanel.NumericalButtonEnabledFeedBack != null)
+ enabledFb = _touchpanel.NumericalButtonEnabledFeedBack[(uint)buttonNumber];
+
+ if (_touchpanel.NumericalButtonDisabledFeedBack != null)
+ disabledFb = _touchpanel.NumericalButtonDisabledFeedBack[(uint)buttonNumber];
+
+ break;
+ }
+ }
+
+ Debug.LogMessage(LogEventLevel.Information, this, "InitializeButton: key-'{0}' enabledFb-'{1}', disabledFb-'{2}'",
+ key, enabledFb ?? (object)"null", disabledFb ?? (object)"null");
+ }
+
+ ///
+ /// Links button feedback if configured
+ ///
+ ///
+ ///
+ public void InitializeButtonFeedback(string key, KeypadButton config)
+ {
+ if (config == null)
+ {
+ Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' config is null, skipping.", key);
+ return;
+ }
+
+ TryParseInt(key, out int buttonNumber);
+
+ // Link up the button feedbacks to the specified device feedback
+ var buttonFeedback = config.Feedback;
+ if (buttonFeedback == null || string.IsNullOrEmpty(buttonFeedback.DeviceKey))
+ {
+ Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedback not configured, skipping.",
+ key);
+ return;
+ }
+
+ Feedback deviceFeedback;
+
+ try
+ {
+ if (!(DeviceManager.GetDeviceForKey(buttonFeedback.DeviceKey) is Device device))
+ {
+ Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedback deviceKey '{1}' not found.",
+ key, buttonFeedback.DeviceKey);
+ return;
+ }
+
+ deviceFeedback = device.GetFeedbackProperty(buttonFeedback.FeedbackName);
+ if (deviceFeedback == null)
+ {
+ Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedbackName property '{1}' not found.",
+ key, buttonFeedback.FeedbackName);
+ return;
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.LogMessage(LogEventLevel.Debug, this, "InitializeButtonFeedback (button '{1}', deviceKey '{2}') Exception Message: {0}",
+ ex.Message, key, buttonFeedback.DeviceKey);
+ Debug.LogMessage(LogEventLevel.Verbose, this, "InitializeButtonFeedback (button '{1}', deviceKey '{2}') Exception StackTrace: {0}",
+ ex.StackTrace, key, buttonFeedback.DeviceKey);
+ if (ex.InnerException != null) Debug.LogMessage(LogEventLevel.Verbose, this, "InitializeButtonFeedback (button '{1}', deviceKey '{2}') InnerException: {0}",
+ ex.InnerException, key, buttonFeedback.DeviceKey);
+
+ return;
+ }
+
+ var boolFeedback = deviceFeedback as BoolFeedback;
+
+ switch (key)
+ {
+ case ("power"):
+ {
+ boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackPower);
+ break;
+ }
+ case ("volumeup"):
+ case ("volumedown"):
+ case ("volumefeedback"):
+ {
+ if (deviceFeedback is IntFeedback intFeedback)
+ {
+ var volumeFeedback = intFeedback;
+ volumeFeedback.LinkInputSig(_touchpanel.VolumeBargraph);
+ }
+ break;
+ }
+ case ("mute"):
+ {
+ boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackMute);
+ break;
+ }
+ default:
+ {
+ boolFeedback?.LinkCrestronFeedback(_touchpanel.Feedbacks[(uint)buttonNumber]);
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Try parse int helper method
+ ///
+ ///
+ ///
+ ///
+ public bool TryParseInt(string str, out int result)
+ {
+ try
+ {
+ result = int.Parse(str);
+ return true;
+ }
+ catch
+ {
+ result = 0;
+ return false;
+ }
+ }
+
+ private void Touchpanel_BaseEvent(GenericBase device, BaseEventArgs args)
+ {
+ Debug.LogMessage(LogEventLevel.Debug, this, "BaseEvent: eventId-'{0}', index-'{1}'", args.EventId, args.Index);
+ }
+
+ private void Touchpanel_ButtonStateChange(GenericBase device, Crestron.SimplSharpPro.DeviceSupport.ButtonEventArgs args)
+ {
+ Debug.LogMessage(LogEventLevel.Debug, this, "ButtonStateChange: buttonNumber-'{0}' buttonName-'{1}', buttonState-'{2}'", args.Button.Number, args.Button.Name, args.NewButtonState);
+ var type = args.NewButtonState.ToString();
+
+ if (_buttons.ContainsKey(args.Button.Number.ToString(CultureInfo.InvariantCulture)))
+ {
+ Press(args.Button.Number.ToString(CultureInfo.InvariantCulture), type);
+ }
+ else if (_buttons.ContainsKey(args.Button.Name.ToString()))
+ {
+ Press(args.Button.Name.ToString(), type);
+ }
+ }
+
+ private void Touchpanel_PanelStateChange(GenericBase device, BaseEventArgs args)
+ {
+ Debug.LogMessage(LogEventLevel.Debug, this, "PanelStateChange: eventId-'{0}', index-'{1}'", args.EventId, args.Index);
+ }
+
+ ///
+ /// Runs the function associated with this button/type. One of the following strings:
+ /// Pressed, Released, Tapped, DoubleTapped, Held, HeldReleased
+ ///
+ ///
+ ///
+ public void Press(string buttonKey, string type)
+ {
+ this.LogVerbose("Press: buttonKey-'{buttonKey}', type-'{type}'", buttonKey, type);
+
+ if (!_buttons.ContainsKey(buttonKey)) return;
+
+ var button = _buttons[buttonKey];
+ if (!button.EventTypes.ContainsKey(type)) return;
+
+ foreach (var eventType in button.EventTypes[type]) DeviceJsonApi.DoDeviceAction(eventType);
+ }
+
+ ///
+ /// ListButtons method
+ ///
+ public void ListButtons()
+ {
+ this.LogVerbose("MPC4 Controller {0} - Available Buttons", Key);
+
+ foreach (var button in _buttons)
+ {
+ this.LogVerbose("Key: {key}", button.Key);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj
index 7be4372d..317fa2d3 100644
--- a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj
+++ b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj
@@ -29,6 +29,6 @@
-
+
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj b/src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj
index d13d1a09..a9223061 100644
--- a/src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj
+++ b/src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj
@@ -33,7 +33,7 @@
-
+
diff --git a/src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj b/src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj
index 235e0899..b0e2dd9f 100644
--- a/src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj
+++ b/src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj
@@ -38,7 +38,7 @@
-
+
diff --git a/src/PepperDash.Essentials/ControlSystem.cs b/src/PepperDash.Essentials/ControlSystem.cs
index 47de4d3e..f2888b8a 100644
--- a/src/PepperDash.Essentials/ControlSystem.cs
+++ b/src/PepperDash.Essentials/ControlSystem.cs
@@ -436,6 +436,25 @@ namespace PepperDash.Essentials
"WARNING: Config file defines processor type as '{deviceType:l}' but actual processor is '{processorType:l}'! Some ports may not be available",
devConf.Type.ToUpper(), Global.ControlSystem.ControllerPrompt.ToUpper());
+ // Check if the processor is an MPC4 model
+ if (prompt.IndexOf("mpc4", StringComparison.OrdinalIgnoreCase) > -1)
+ {
+ Debug.LogMessage(LogEventLevel.Information, "MPC4 processor type detected. Adding Mpc4TouchpanelController.");
+
+ var butToken = devConf.Properties["buttons"];
+ if (butToken == null)
+ {
+ Debug.LogMessage(LogEventLevel.Warning,
+ "Error: Unable to deserialize buttons collection for device: {deviceKey}", devConf.Key);
+ continue;
+ }
+
+ var buttons = Newtonsoft.Json.JsonConvert.DeserializeObject>(butToken.ToString());
+ var tpController = new Core.Touchpanels.Mpc4TouchpanelController(
+ string.Format("{0}-keypadButtons", devConf.Key), devConf.Name, Global.ControlSystem, buttons);
+
+ DeviceManager.AddDevice(tpController);
+ }
continue;
}
diff --git a/src/PepperDash.Essentials/PepperDash.Essentials.csproj b/src/PepperDash.Essentials/PepperDash.Essentials.csproj
index 20a42ffd..cb83bf84 100644
--- a/src/PepperDash.Essentials/PepperDash.Essentials.csproj
+++ b/src/PepperDash.Essentials/PepperDash.Essentials.csproj
@@ -48,7 +48,7 @@
-
+