feat(password-management): update password client and manager methods, added modules

- Modified Password Management to allow username/password input for validation
- Introduced PepperDash_Core_Password_Client_A4sA3s_v02.00.usp for handling password validation and management.
- Added PepperDash_Core_Password_Manager_A4sA3s_v02.00.usp to manage multiple passwords and user authentication.
- Created corresponding .ush files for both modules to define inputs, outputs, and parameters.
- Included a compiled zip file for the password management system.
- Updated project file to include new password management functionalities and ensure compatibility with existing components.
This commit is contained in:
jdevito 2026-02-19 21:00:45 -06:00
parent 28f3ca3199
commit afa725b44e
15 changed files with 1767 additions and 1137 deletions

View file

@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// JSON password configuration
/// </summary>
public class PasswordConfig
{
/// <summary>
/// Password object configured password
/// </summary>
public string password { get; set; }
/// <summary>
/// Constructor
/// </summary>
public PasswordConfig()
{
}
}
}

View file

@ -1,149 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement
{
// Example JSON password array configuration object
//{
// "global":{
// "passwords":[
// {
// "key": "Password01",
// "name": "Technician Password",
// "enabled": true,
// "password": "1988"
// }
// ]
// }
//}
/// <summary>
/// JSON password array configuration object
/// </summary>
//public class PasswordConfig
//{
// /// <summary>
// /// Key used to search for object in JSON array
// /// </summary>
// public string key { get; set; }
// /// <summary>
// /// Friendly name of password object
// /// </summary>
// public string name { get; set; }
// /// <summary>
// /// Password object enabled
// /// </summary>
// public bool enabled { get; set; }
// /// <summary>
// ///
// /// </summary>
// public ushort simplEnabled
// {
// get { return (ushort)(enabled ? 1 : 0); }
// set { enabled = Convert.ToBoolean(value); }
// }
// /// <summary>
// /// Password object configured password
// /// </summary>
// public string password { get; set; }
// /// <summary>
// /// Password type
// /// </summary>
// private int type { get; set; }
// /// <summary>
// /// Password Type for S+
// /// </summary>
// public ushort simplType
// {
// get { return Convert.ToUInt16(type); }
// set { type = value; }
// }
// /// <summary>
// /// Password path
// /// **FUTURE** implementation of saving passwords recieved from Fusion or other external sources back to config
// /// </summary>
// public string path { get; set; }
// /// <summary>
// /// Constructor
// /// </summary>
// public PasswordConfig()
// {
// simplEnabled = 0;
// simplType = 0;
// }
//}
// Example JSON password collections configuration object
//{
// "global": {
// "passwords": {
// "1": {
// "name": "Technician Password",
// "password": "2468"
// },
// "2": {
// "name": "System Password",
// "password": "123456"
// },
// "3": {
// "name": "Master Password",
// "password": "abc123"
// },
// "5": {
// "name": "Backdoor Password",
// "password": "1988"
// },
// "10": {
// "name": "Backdoor Password",
// "password": "1988"
// }
// }
// }
//}
/// <summary>
/// JSON password array configuration object
/// </summary>
public class PasswordConfig
{
/// <summary>
/// Password object configured password
/// </summary>
public string password { get; set; }
/// <summary>
/// Constructor
/// </summary>
public PasswordConfig()
{
}
}
/// <summary>
/// Global JSON object
/// </summary>
//public class GlobalConfig
//{
// //public List<PasswordConfig> passwords { get; set; }
// public Dictionary<uint, PasswordConfig> passwords { get; set; }
// /// <summary>
// /// Constructor
// /// </summary>
// public GlobalConfig()
// {
// }
//}
/// <summary>
/// Root JSON object
/// </summary>
//public class RootObject
//{
// public GlobalConfig global { get; set; }
//}
}

View file

@ -1,207 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement
{
public class PasswordClient
{
/// <summary>
/// Password Client
/// </summary>
public PasswordConfig Client { get; set; }
/// <summary>
/// Used to build the password entered by the user
/// </summary>
public string PasswordToValidate { get; set; }
/// <summary>
/// Boolean event
/// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary>
/// Ushort event
/// </summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// <summary>
/// String event
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// Constructor
/// </summary>
public PasswordClient()
{
}
/// <summary>
/// Initialize method
/// </summary>
/// <param name="key"></param>
public void Initialize(string key)
{
OnBoolChange(false, 0, PasswordManagementConstants.BoolEvaluatedChange);
Client = new PasswordConfig();
PasswordToValidate = "";
// there has to be a better way to get the index of the current index of password
ushort i = 0;
foreach (var password in PasswordManager.Passwords)
{
i++;
OnUshrtChange((ushort)password.Key, (ushort)password.Key, PasswordManagementConstants.PasswordKey);
}
OnBoolChange(true, 0, PasswordManagementConstants.BoolEvaluatedChange);
}
/// <summary>
/// Retrieves password by key
/// </summary>
/// <param name="key"></param>
//public void GetPasswordByKey(string key)
//{
// if (string.IsNullOrEmpty(key))
// {
// Debug.Console(1, "PassowrdClient.GetPasswordByKey failed:\rKey {0} is null or empty", key);
// return;
// }
// PasswordConfig password = PasswordManager.Passwords.FirstOrDefault(p => p.key.Equals(key));
// if (password == null)
// {
// OnUshrtChange(0, 0, PasswordManagementConstants.SelectedPasswordLength);
// return;
// }
// Client = password;
// OnUshrtChange((ushort)Client.password.Length, 0, PasswordManagementConstants.SelectedPasswordLength);
// OnStringChange(Client.key, 0, PasswordManagementConstants.PasswordKeySelected);
//}
/// <summary>
/// Retrieve password by index
/// </summary>
/// <param name="index"></param>
public void GetPasswordByIndex(ushort key)
{
PasswordConfig pw = PasswordManager.Passwords[key];
if (pw == null)
{
OnUshrtChange(0, 0, PasswordManagementConstants.SelectedPasswordLength);
return;
}
Client = pw;
OnUshrtChange((ushort)Client.password.Length, 0, PasswordManagementConstants.SelectedPasswordLength);
OnUshrtChange(key, 0, PasswordManagementConstants.PasswordKeySelected);
}
/// <summary>
/// Password validation method
/// </summary>
/// <param name="password"></param>
public void ValidatePassword(string password)
{
if (string.IsNullOrEmpty(password))
return;
if (string.Equals(Client.password, password))
{
OnBoolChange(true, 0, PasswordManagementConstants.PasswordIsValid);
}
else
{
OnBoolChange(true, 0, PasswordManagementConstants.PasswordIsInvalid);
}
OnBoolChange(false, 0, PasswordManagementConstants.PasswordIsValid);
OnBoolChange(false, 0, PasswordManagementConstants.PasswordIsInvalid);
ClearPassword();
}
/// <summary>
/// Builds the user entered passwrod string, will attempt to validate the user entered
/// password against the selected password when the length of the 2 are equal
/// </summary>
/// <param name="data"></param>
public void BuildPassword(string data)
{
PasswordToValidate = String.Concat(PasswordToValidate, data);
OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedChange);
if (PasswordToValidate.Length == Client.password.Length)
ValidatePassword(PasswordToValidate);
}
/// <summary>
/// Clears the user entered password and resets the LEDs
/// </summary>
public void ClearPassword()
{
PasswordToValidate = "";
OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedChange);
for(var i = 1; i <= Client.password.Length; i++)
OnBoolChange(false, (ushort)i, PasswordManagementConstants.PasswordLedChange);
}
/// <summary>
/// Protected boolean change event handler
/// </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;
if (handler != null)
{
var args = new BoolChangeEventArgs(state, type);
args.Index = index;
BoolChange(this, args);
}
}
/// <summary>
/// Protected ushort change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnUshrtChange(ushort value, ushort index, ushort type)
{
var handler = UshrtChange;
if (handler != null)
{
var args = new UshrtChangeEventArgs(value, type);
args.Index = index;
UshrtChange(this, args);
}
}
/// <summary>
/// Protected string change event handler
/// </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;
if (handler != null)
{
var args = new StringChangeEventArgs(value, type);
args.Index = index;
StringChange(this, args);
}
}
}
}

View file

@ -1,233 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Crestron.SimplSharp;
using PepperDash.Core.JsonToSimpl;
using PepperDash.Core.JsonStandardObjects;
namespace PepperDash.Core.PasswordManagement
{
public class PasswordManager
{
/// <summary>
/// List of passwords configured
/// </summary>
public static Dictionary<uint, PasswordConfig> Passwords = new Dictionary<uint, PasswordConfig>();
private Dictionary<uint, PasswordConfig> TempPasswords = new Dictionary<uint, PasswordConfig>();
CTimer UpdateTimer;
public long UpdateTimerElapsedMs = 5000;
/// <summary>
/// Boolean event
/// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary>
/// Ushort event
/// </summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// <summary>
/// String event
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// Constructor
/// </summary>
public PasswordManager()
{
Passwords.Clear();
}
/// <summary>
/// Initialize method
/// </summary>
/// <param name="key"></param>
/// <param name="uniqueId"></param>
//public void Initialize(string uniqueId, string key)
//{
// OnBoolChange(false, 0, PasswordManagementConstants.BoolEvaluatedChange);
// try
// {
// if(string.IsNullOrEmpty(uniqueId) || string.IsNullOrEmpty(key))
// {
// Debug.Console(1, "PasswordManager.Initialize({0}, {1}) null or empty parameters", uniqueId, key);
// return;
// }
// JsonToSimplMaster master = J2SGlobal.GetMasterByFile(uniqueId);
// if(master == null)
// {
// Debug.Console(1, "PassowrdManager.Initialize failed:\rCould not find JSON file with uniqueID {0}", uniqueId);
// return;
// }
// var global = master.JsonObject.ToObject<RootObject>().global;
// var passwords = global.passwords;
// if(passwords == null)
// {
// Debug.Console(1, "PasswordManager.Initialize failed:\rCould not find password object");
// return;
// }
// foreach(var password in passwords)
// {
// if (password != null)
// {
// var index = passwords.IndexOf(password);
// password.path = string.Format("global.passwords[{0}]", index);
// Debug.Console(1, "PasswordManager.Initialize: {0}, {1}, {2}, {3}, {4}, {5}", password.key, password.name, password.simplEnabled, password.simplType, password.password, password.path);
// //AddPassword(password);
// OnStringChange(password.path, (ushort)index, PasswordManagementConstants.FullPathToPassword);
// OnStringChange(password.key, (ushort)index, PasswordManagementConstants.PasswordKey);
// }
// }
// OnUshrtChange(Convert.ToUInt16(Passwords.Count), 0, PasswordManagementConstants.PasswordListCount);
// }
// catch(Exception e)
// {
// var msg = string.Format("PasswordManager.Initialize({0}, {1}) failed:\r{2}", uniqueId, key, e.Message);
// CrestronConsole.PrintLine(msg);
// ErrorLog.Error(msg);
// }
// finally
// {
// OnBoolChange(true, 0, PasswordManagementConstants.BoolEvaluatedChange);
// }
//}
/// <summary>
/// Adds password to the list
/// </summary>
/// <param name="password"></param>
//private void AddPassword(PasswordConfig password)
//{
// if (password == null)
// return;
// var item = Passwords.FirstOrDefault(i => i.key.Equals(password.key));
// if (item != null)
// Passwords.Remove(item);
// Passwords.Add(password);
// Passwords.Sort((x, y) => string.Compare(x.key, y.key));
//}
/// <summary>
/// Removes password from the list
/// </summary>
/// <param name="password"></param>
//private void RemovePassword(PasswordConfig password)
//{
// if (password == null)
// return;
// var item = Passwords.FirstOrDefault(i => i.key.Equals(password.key));
// if (item != null)
// Passwords.Remove(item);
//}
/// <summary>
/// Updates password stored in the dictonary
/// </summary>
/// <param name="uniqueId"></param>
/// <param name="key"></param>
/// <param name="password"></param>
public void UpdatePassword(ushort key, string password)
{
if (string.IsNullOrEmpty(password))
return;
var pw = TempPasswords[key];
if (pw == null)
{
pw = new PasswordConfig();
}
pw.password = password;
if (UpdateTimer == null)
{
// (o) => SavePasswords removes the need to create a callback method that takes in an object
UpdateTimer = new CTimer((o) => StorePassword(), UpdateTimerElapsedMs);
}
else
{
UpdateTimer.Reset();
}
}
/// <summary>
/// Stores the updated passwords in TempPassword in the Passwords dictionary
/// </summary>
private void StorePassword()
{
UpdateTimer.Stop();
foreach (var tempPw in TempPasswords)
{
Passwords[tempPw.Key] = tempPw.Value;
}
TempPasswords.Clear();
}
/// <summary>
/// Protected boolean change event handler
/// </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;
if (handler != null)
{
var args = new BoolChangeEventArgs(state, type);
args.Index = index;
BoolChange(this, args);
}
}
/// <summary>
/// Protected ushort change event handler
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnUshrtChange(ushort value, ushort index, ushort type)
{
var handler = UshrtChange;
if (handler != null)
{
var args = new UshrtChangeEventArgs(value, type);
args.Index = index;
UshrtChange(this, args);
}
}
/// <summary>
/// Protected string change event handler
/// </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;
if (handler != null)
{
var args = new StringChangeEventArgs(value, type);
args.Index = index;
StringChange(this, args);
}
}
}
}

View file

@ -1,7 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement namespace PepperDash.Core.PasswordManagement
@ -11,14 +8,16 @@ namespace PepperDash.Core.PasswordManagement
/// </summary> /// </summary>
public class PasswordClient public class PasswordClient
{ {
/// <summary>
/// Password selected key
/// </summary>
public string Username { get; set; }
/// <summary> /// <summary>
/// Password selected /// Password selected
/// </summary> /// </summary>
public string Password { get; set; } public string Password { get; set; }
/// <summary>
/// Password selected key
/// </summary>
public ushort Key { get; set; }
/// <summary> /// <summary>
/// Used to build the password entered by the user /// Used to build the password entered by the user
/// </summary> /// </summary>
@ -42,7 +41,11 @@ namespace PepperDash.Core.PasswordManagement
/// </summary> /// </summary>
public PasswordClient() public PasswordClient()
{ {
PasswordManager.PasswordChange += new EventHandler<StringChangeEventArgs>(PasswordManager_PasswordChange); PasswordManager.Initialized += (sender, args) => Initialize();
PasswordManager.PasswordChange += PasswordManager_PasswordChange;
if (PasswordManager.IsInitialized)
Initialize();
} }
/// <summary> /// <summary>
@ -50,52 +53,108 @@ namespace PepperDash.Core.PasswordManagement
/// </summary> /// </summary>
public void Initialize() public void Initialize()
{ {
OnBoolChange(false, 0, PasswordManagementConstants.PasswordInitializedChange); OnBoolChange(false, 0, PasswordConstants.Initialized);
Password = ""; Username = string.Empty;
PasswordToValidate = ""; Password = string.Empty;
PasswordToValidate = string.Empty;
OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange); OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordConstants.Count);
OnBoolChange(true, 0, PasswordManagementConstants.PasswordInitializedChange); OnUshrtChange(0, 0, PasswordConstants.PasswordLength);
OnStringChange(string.Empty, 0, PasswordConstants.UsernameValidated);
OnStringChange("Password client initilaized", 0, PasswordConstants.Message);
OnBoolChange(true, 0, PasswordConstants.Initialized);
} }
/// <summary> /// <summary>
/// Retrieve password by index /// Sends clear/0 values to S+ wrapper
/// </summary> /// </summary>
/// <param name="key"></param> public void ClearOutputs()
public void GetPasswordByIndex(ushort key)
{ {
OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange); //OnBoolChange(false, 0, PasswordConstants.UsernameValidated);
OnUshrtChange(0, 0, PasswordConstants.PasswordLength);
OnStringChange(string.Empty, 0, PasswordConstants.UsernameValidated);
OnStringChange(string.Empty, 0, PasswordConstants.Message);
}
Key = key; /// <summary>
/// Sends clear/0 values to S+ wrapper
/// </summary>
/// <param name="result"></param>
public void UpdateOutputs(PasswordValidationResult result)
{
OnBoolChange(result.IsValid, 0, PasswordConstants.UsernameValidated);
OnUshrtChange((ushort)(string.IsNullOrEmpty(result.Password) ? 0 : result.Password.Length), 0, PasswordConstants.PasswordLength);
OnStringChange(string.Empty, 0, PasswordConstants.UsernameValidated);
OnStringChange(result.Message, 0, PasswordConstants.Message);
}
var pw = PasswordManager.Passwords[Key]; /// <summary>
if (pw == null) /// Validate username
/// </summary>
/// <param name="username"></param>
public void ValidateUsername(string username)
{
if (string.IsNullOrEmpty(username))
{ {
OnUshrtChange(0, 0, PasswordManagementConstants.PasswordLengthChange); OnStringChange("Username is null or empty", 0, PasswordConstants.Message);
return; return;
} }
Password = pw; var result = PasswordManager.ValidateUsername(username);
OnUshrtChange((ushort)Password.Length, 0, PasswordManagementConstants.PasswordLengthChange); if (!result.IsValid)
OnUshrtChange(key, 0, PasswordManagementConstants.PasswordSelectIndexChange); {
} UpdateOutputs(result);
return;
}
Username = username;
Password = result.Password;
PasswordToValidate = string.Empty;
OnStringChange(Username, 0, PasswordConstants.UsernameValidated);
OnBoolChange(result.IsValid, 0, PasswordConstants.UsernameValidated);
OnUshrtChange((ushort)result.Password.Length, 0, PasswordConstants.PasswordLength);
OnStringChange(result.Message, 0, PasswordConstants.Message);
}
/// <summary> /// <summary>
/// Password validation method /// Validate username and passowrd
/// </summary> /// </summary>
/// <param name="username"></param>
/// <param name="password"></param> /// <param name="password"></param>
public void ValidatePassword(string password) public void ValidateUsernameAndPassword(string username, string password)
{ {
if (string.IsNullOrEmpty(password)) if (string.IsNullOrEmpty(username))
{
OnStringChange("Username is null or empty", 0, PasswordConstants.Message);
return; return;
}
if (string.Equals(Password, password)) if (string.IsNullOrEmpty(password))
OnBoolChange(true, 0, PasswordManagementConstants.PasswordValidationChange); {
else OnStringChange("Password is null or empty", 0, PasswordConstants.Message);
OnBoolChange(false, 0, PasswordManagementConstants.PasswordValidationChange); return;
}
ClearPassword(); var result = PasswordManager.ValidateUsernameAndPassword(username, password);
if (!result.IsValid)
{
UpdateOutputs(result);
return;
}
OnBoolChange(result.IsValid, 0, PasswordConstants.PasswordValidated);
OnStringChange(result.Message, 0, PasswordConstants.Message);
// Clear entered password and reset outputs after a delay (make configurable as needed)
const long clearDelayMs = 5000;
new CTimer(_ =>
{
ClearPassword();
ClearOutputs();
}, clearDelayMs);
} }
/// <summary> /// <summary>
@ -106,10 +165,22 @@ namespace PepperDash.Core.PasswordManagement
public void BuildPassword(string data) public void BuildPassword(string data)
{ {
PasswordToValidate = String.Concat(PasswordToValidate, data); PasswordToValidate = String.Concat(PasswordToValidate, data);
OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedFeedbackChange); OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordConstants.LedFeedback);
if (PasswordToValidate.Length == Password.Length) if (string.IsNullOrEmpty(Password))
ValidatePassword(PasswordToValidate); {
OnStringChange("Cannot validate password, password is null or empty", 0, PasswordConstants.Message);
return;
}
if (PasswordToValidate.Length != Password.Length) return;
if (string.IsNullOrEmpty(Username))
{
OnStringChange("Cannot validate password, username is null or empty", 0, PasswordConstants.Message);
return;
}
ValidateUsernameAndPassword(Username, PasswordToValidate);
} }
/// <summary> /// <summary>
@ -117,8 +188,8 @@ namespace PepperDash.Core.PasswordManagement
/// </summary> /// </summary>
public void ClearPassword() public void ClearPassword()
{ {
PasswordToValidate = ""; PasswordToValidate = string.Empty;
OnBoolChange(false, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedFeedbackChange); OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordConstants.LedFeedback);
} }
/// <summary> /// <summary>
@ -126,12 +197,23 @@ namespace PepperDash.Core.PasswordManagement
/// </summary> /// </summary>
public void DeletePasswordCharacter() public void DeletePasswordCharacter()
{ {
ushort PasswordLengthBeforeDelete = (ushort)PasswordToValidate.Length; if (string.IsNullOrEmpty(PasswordToValidate))
return;
var previousLength = (ushort)PasswordToValidate.Length;
// Remove last entered character
PasswordToValidate = PasswordToValidate.Substring(0, PasswordToValidate.Length - 1); PasswordToValidate = PasswordToValidate.Substring(0, PasswordToValidate.Length - 1);
OnBoolChange(false, (ushort)PasswordLengthBeforeDelete, PasswordManagementConstants.PasswordLedFeedbackChange);
// Verify if OnStringChange is needed to update the S+ wrapper with the entered PasswordToValidate // Turn off the last LED that was on (old length index)
OnBoolChange(false, previousLength, PasswordConstants.LedFeedback);
// Send updated length back to S+
OnUshrtChange((ushort)PasswordToValidate.Length, 0, PasswordConstants.PasswordLength);
} }
#region event handlers
/// <summary> /// <summary>
/// Protected boolean change event handler /// Protected boolean change event handler
/// </summary> /// </summary>
@ -141,12 +223,10 @@ namespace PepperDash.Core.PasswordManagement
protected void OnBoolChange(bool state, ushort index, ushort type) protected void OnBoolChange(bool state, ushort index, ushort type)
{ {
var handler = BoolChange; var handler = BoolChange;
if (handler != null) if (handler == null) return;
{
var args = new BoolChangeEventArgs(state, type); var args = new BoolChangeEventArgs(state, type) {Index = index};
args.Index = index; BoolChange(this, args);
BoolChange(this, args);
}
} }
/// <summary> /// <summary>
@ -158,12 +238,10 @@ namespace PepperDash.Core.PasswordManagement
protected void OnUshrtChange(ushort value, ushort index, ushort type) protected void OnUshrtChange(ushort value, ushort index, ushort type)
{ {
var handler = UshrtChange; var handler = UshrtChange;
if (handler != null) if (handler == null) return;
{
var args = new UshrtChangeEventArgs(value, type); var args = new UshrtChangeEventArgs(value, type) {Index = index};
args.Index = index; UshrtChange(this, args);
UshrtChange(this, args);
}
} }
/// <summary> /// <summary>
@ -175,12 +253,20 @@ namespace PepperDash.Core.PasswordManagement
protected void OnStringChange(string value, ushort index, ushort type) protected void OnStringChange(string value, ushort index, ushort type)
{ {
var handler = StringChange; var handler = StringChange;
if (handler != null) if (handler == null) return;
{
var args = new StringChangeEventArgs(value, type); var args = new StringChangeEventArgs(value, type) { Index = index };
args.Index = index; StringChange(this, args);
StringChange(this, args); }
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
protected void PasswordManager_Initialized(object sender, BoolChangeEventArgs args)
{
Initialize();
} }
/// <summary> /// <summary>
@ -190,13 +276,12 @@ namespace PepperDash.Core.PasswordManagement
/// <param name="args"></param> /// <param name="args"></param>
protected void PasswordManager_PasswordChange(object sender, StringChangeEventArgs args) protected void PasswordManager_PasswordChange(object sender, StringChangeEventArgs args)
{ {
//throw new NotImplementedException(); if (Username == args.StringValue && args.Type == PasswordConstants.PasswordUpdated)
if (Key == args.Index)
{ {
//PasswordSelectedKey = args.Index; // TODO - If the current username password changes, do something
//PasswordSelected = args.StringValue;
GetPasswordByIndex(args.Index);
} }
} }
#endregion
} }
} }

View file

@ -0,0 +1,24 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// JSON password configuration
/// </summary>
public class PasswordConfig
{
/// <summary>
/// Dictionary of user passwords. Key is the username, value is the password
/// </summary>
[JsonProperty("passwords")]
public Dictionary<string, string> Passwords { get; set; }
/// <summary>
/// Constructor
/// </summary>
public PasswordConfig()
{
}
}
}

View file

@ -1,57 +1,73 @@
using System; 
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement namespace PepperDash.Core.PasswordManagement
{ {
/// <summary> /// <summary>
/// Constants /// Constants
/// </summary> /// </summary>
public class PasswordManagementConstants public class PasswordConstants
{ {
/// <summary> /// <summary>
/// Generic boolean value change constant /// Generic boolean value change constant
/// </summary> /// </summary>
public const ushort BoolValueChange = 1; public const ushort BoolValueChange = 1;
/// <summary> /// <summary>
/// Evaluated boolean change constant /// Evaluated boolean change constant
/// </summary> /// </summary>
public const ushort PasswordInitializedChange = 2; public const ushort Initialized = 2;
/// <summary> /// <summary>
/// Update busy change const /// Update busy change const
/// </summary> /// </summary>
public const ushort PasswordUpdateBusyChange = 3; public const ushort UpdateBusy = 3;
/// <summary>
/// Username is valid change constant
/// </summary>
public const ushort UsernameValidated = 4;
/// <summary> /// <summary>
/// Password is valid change constant /// Password is valid change constant
/// </summary> /// </summary>
public const ushort PasswordValidationChange = 4; public const ushort PasswordValidated = 5;
/// <summary> /// <summary>
/// Password LED change constant /// Password LED change constant
/// </summary> /// </summary>
public const ushort PasswordLedFeedbackChange = 5; public const ushort LedFeedback = 6;
/// <summary> /// <summary>
/// Generic ushort value change constant /// Generic ushort value change constant
/// </summary> /// </summary>
public const ushort UshrtValueChange = 101; public const ushort UshrtValueChange = 101;
/// <summary> /// <summary>
/// Password count /// Password count
/// </summary> /// </summary>
public const ushort PasswordManagerCountChange = 102; public const ushort Count = 102;
/// <summary>
/// Password selecte index change constant
/// </summary>
public const ushort PasswordSelectIndexChange = 103;
/// <summary> /// <summary>
/// Password length /// Password length
/// </summary> /// </summary>
public const ushort PasswordLengthChange = 104; public const ushort PasswordLength = 104;
/// <summary> /// <summary>
/// Generic string value change constant /// Generic string value change constant
/// </summary> /// </summary>
public const ushort StringValueChange = 201; public const ushort StringValueChange = 201;
/// <summary>
/// Password message constant, used to send the password string to clients when a password is updated
/// </summary>
public const ushort Message = 202;
/// <summary>
/// Password updated
/// </summary>
public const ushort PasswordUpdated = 203;
} }
} }

View file

@ -1,12 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using PepperDash.Core.JsonToSimpl;
using PepperDash.Core.JsonStandardObjects;
namespace PepperDash.Core.PasswordManagement namespace PepperDash.Core.PasswordManagement
{ {
@ -18,16 +12,22 @@ namespace PepperDash.Core.PasswordManagement
/// <summary> /// <summary>
/// Public dictionary of known passwords /// Public dictionary of known passwords
/// </summary> /// </summary>
public static Dictionary<uint, string> Passwords = new Dictionary<uint, string>(); public static Dictionary<string, string> Passwords = new Dictionary<string, string>();
/// <summary> /// <summary>
/// Private dictionary, used when passwords are updated /// Indicates whether the manager has been initialized
/// </summary> /// </summary>
private Dictionary<uint, string> _passwords = new Dictionary<uint, string>(); public static bool IsInitialized { get; private set; }
/// <summary>
/// Tracks keys changed during the debounce window for notification
/// </summary>
private readonly List<string> _pendingChanges = new List<string>();
/// <summary> /// <summary>
/// Timer used to wait until password changes have stopped before updating the dictionary /// Timer used to wait until password changes have stopped before updating the dictionary
/// </summary> /// </summary>
CTimer PasswordTimer; CTimer _passwordTimer;
/// <summary> /// <summary>
/// Timer length /// Timer length
/// </summary> /// </summary>
@ -51,11 +51,15 @@ namespace PepperDash.Core.PasswordManagement
public static event EventHandler<StringChangeEventArgs> PasswordChange; public static event EventHandler<StringChangeEventArgs> PasswordChange;
/// <summary> /// <summary>
/// Constructor /// Event to notify clients when the manager has been initialized
/// </summary>
public static event EventHandler<BoolChangeEventArgs> Initialized;
/// <summary>
/// Constructor (empty constructor required by S+)
/// </summary> /// </summary>
public PasswordManager() public PasswordManager()
{ {
} }
/// <summary> /// <summary>
@ -64,12 +68,17 @@ namespace PepperDash.Core.PasswordManagement
public void Initialize() public void Initialize()
{ {
if (Passwords == null) if (Passwords == null)
Passwords = new Dictionary<uint, string>(); {
Passwords = new Dictionary<string, string>();
}
if (_passwords == null) OnBoolChange(true, 0, PasswordConstants.Initialized);
_passwords = new Dictionary<uint, string>();
OnBoolChange(true, 0, PasswordManagementConstants.PasswordInitializedChange); IsInitialized = true;
var handler = Initialized;
if (handler != null)
handler(this, new BoolChangeEventArgs(true, PasswordConstants.Initialized));
} }
/// <summary> /// <summary>
@ -77,10 +86,10 @@ namespace PepperDash.Core.PasswordManagement
/// </summary> /// </summary>
/// <param name="key"></param> /// <param name="key"></param>
/// <param name="password"></param> /// <param name="password"></param>
public void UpdatePassword(ushort key, string password) public void UpdatePassword(string key, string password)
{ {
// validate the parameters // validate the parameters
if (key > 0 && string.IsNullOrEmpty(password)) if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(password))
{ {
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: key [{0}] or password are not valid", key, password)); Debug.Console(1, string.Format("PasswordManager.UpdatePassword: key [{0}] or password are not valid", key, password));
return; return;
@ -88,24 +97,21 @@ namespace PepperDash.Core.PasswordManagement
try try
{ {
// if key exists, update the value Passwords[key] = password;
if(_passwords.ContainsKey(key)) if (!_pendingChanges.Contains(key))
_passwords[key] = password; _pendingChanges.Add(key);
// else add the key & value
else
_passwords.Add(key, password);
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: _password[{0}] = {1}", key, _passwords[key])); Debug.Console(1, string.Format("PasswordManager.UpdatePassword: Passwords[{0}] = {1}", key, Passwords[key]));
if (PasswordTimer == null) if (_passwordTimer == null)
{ {
PasswordTimer = new CTimer((o) => PasswordTimerElapsed(), PasswordTimerElapsedMs); _passwordTimer = new CTimer((o) => PasswordTimerElapsed(), PasswordTimerElapsedMs);
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Started")); Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Started"));
OnBoolChange(true, 0, PasswordManagementConstants.PasswordUpdateBusyChange); OnBoolChange(true, 0, PasswordConstants.UpdateBusy);
} }
else else
{ {
PasswordTimer.Reset(PasswordTimerElapsedMs); _passwordTimer.Reset(PasswordTimerElapsedMs);
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Reset")); Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Reset"));
} }
} }
@ -116,6 +122,62 @@ namespace PepperDash.Core.PasswordManagement
} }
} }
/// <summary>
/// Helper method for debugging to see what passwords are in the lists
/// </summary>
public void ListEntries()
{
Debug.Console(0, "PasswordManager.ListEntries:\r");
foreach (var pw in Passwords)
{
var maskedValue = string.IsNullOrEmpty(pw.Value) ? string.Empty : new string('*', pw.Value.Length);
Debug.Console(0, "Passwords[{0}]: {1}\r", pw.Key, maskedValue);
}
}
/// <summary>
/// Validates the username against the known entries
/// </summary>
/// <param name="username"></param>
public static PasswordValidationResult ValidateUsername(string username)
{
if (Passwords == null)
return PasswordValidationResult.Failure("No entires defined, verify list is initilaized");
if (string.IsNullOrEmpty(username))
return PasswordValidationResult.Failure("Username or password is empty");
string storedPassword;
return !Passwords.TryGetValue(username, out storedPassword)
? PasswordValidationResult.Failure(string.Format("Username '{0}' not found", username))
: PasswordValidationResult.Success("Valid username", storedPassword);
}
/// <summary>
/// Validates the username password against the known entries
/// </summary>
/// <param name="username"></param>
/// <param name="password"></param>
public static PasswordValidationResult ValidateUsernameAndPassword(string username, string password)
{
if (Passwords == null)
return PasswordValidationResult.Failure("No entires defined, verify list is initilaized");
if (string.IsNullOrEmpty(username))
return PasswordValidationResult.Failure("Username is empty or null");
if(string.IsNullOrEmpty(password))
return PasswordValidationResult.Failure("Password is empty or null");
string storedPassword;
if (!Passwords.TryGetValue(username, out storedPassword))
return PasswordValidationResult.Failure(string.Format("Username '{0}' not found", username));
return !string.Equals(storedPassword, password, StringComparison.Ordinal)
? PasswordValidationResult.Failure("Invalid password, verify password and try again")
: PasswordValidationResult.Success("Valid credentials, login was successfull", storedPassword);
}
/// <summary> /// <summary>
/// CTimer callback function /// CTimer callback function
/// </summary> /// </summary>
@ -123,29 +185,21 @@ namespace PepperDash.Core.PasswordManagement
{ {
try try
{ {
PasswordTimer.Stop(); _passwordTimer.Stop();
Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: CTimer Stopped")); Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: CTimer Stopped"));
OnBoolChange(false, 0, PasswordManagementConstants.PasswordUpdateBusyChange); OnBoolChange(false, 0, PasswordConstants.UpdateBusy);
foreach (var pw in _passwords)
foreach (var key in _pendingChanges)
{ {
// if key exists, continue string value;
if (Passwords.ContainsKey(pw.Key)) if (!Passwords.TryGetValue(key, out value)) continue;
{
Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: pw.key[{0}] = {1}", pw.Key, pw.Value)); Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: Notifying change for [{0}]", key));
if (Passwords[pw.Key] != _passwords[pw.Key]) OnPasswordChange(key, 0, PasswordConstants.PasswordUpdated);
{
Passwords[pw.Key] = _passwords[pw.Key];
Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: Updated Password[{0} = {1}", pw.Key, Passwords[pw.Key]));
OnPasswordChange(Passwords[pw.Key], (ushort)pw.Key, PasswordManagementConstants.StringValueChange);
}
}
// else add the key & value
else
{
Passwords.Add(pw.Key, pw.Value);
}
} }
OnUshrtChange((ushort)Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange);
_pendingChanges.Clear();
OnUshrtChange((ushort)Passwords.Count, 0, PasswordConstants.Count);
} }
catch (Exception e) catch (Exception e)
{ {
@ -163,18 +217,8 @@ namespace PepperDash.Core.PasswordManagement
PasswordTimerElapsedMs = Convert.ToInt64(time); PasswordTimerElapsedMs = Convert.ToInt64(time);
} }
/// <summary>
/// Helper method for debugging to see what passwords are in the lists #region event handlers
/// </summary>
public void ListPasswords()
{
Debug.Console(0, "PasswordManager.ListPasswords:\r");
foreach (var pw in Passwords)
Debug.Console(0, "Passwords[{0}]: {1}\r", pw.Key, pw.Value);
Debug.Console(0, "\n");
foreach (var pw in _passwords)
Debug.Console(0, "_passwords[{0}]: {1}\r", pw.Key, pw.Value);
}
/// <summary> /// <summary>
/// Protected boolean change event handler /// Protected boolean change event handler
@ -185,12 +229,10 @@ namespace PepperDash.Core.PasswordManagement
protected void OnBoolChange(bool state, ushort index, ushort type) protected void OnBoolChange(bool state, ushort index, ushort type)
{ {
var handler = BoolChange; var handler = BoolChange;
if (handler != null) if (handler == null) return;
{
var args = new BoolChangeEventArgs(state, type); var args = new BoolChangeEventArgs(state, type) {Index = index};
args.Index = index; BoolChange(this, args);
BoolChange(this, args);
}
} }
/// <summary> /// <summary>
@ -202,12 +244,10 @@ namespace PepperDash.Core.PasswordManagement
protected void OnUshrtChange(ushort value, ushort index, ushort type) protected void OnUshrtChange(ushort value, ushort index, ushort type)
{ {
var handler = UshrtChange; var handler = UshrtChange;
if (handler != null) if (handler == null) return;
{
var args = new UshrtChangeEventArgs(value, type); var args = new UshrtChangeEventArgs(value, type) {Index = index};
args.Index = index; UshrtChange(this, args);
UshrtChange(this, args);
}
} }
/// <summary> /// <summary>
@ -219,12 +259,10 @@ namespace PepperDash.Core.PasswordManagement
protected void OnStringChange(string value, ushort index, ushort type) protected void OnStringChange(string value, ushort index, ushort type)
{ {
var handler = StringChange; var handler = StringChange;
if (handler != null) if (handler == null) return;
{
var args = new StringChangeEventArgs(value, type); var args = new StringChangeEventArgs(value, type) {Index = index};
args.Index = index; StringChange(this, args);
StringChange(this, args);
}
} }
/// <summary> /// <summary>
@ -236,12 +274,12 @@ namespace PepperDash.Core.PasswordManagement
protected void OnPasswordChange(string value, ushort index, ushort type) protected void OnPasswordChange(string value, ushort index, ushort type)
{ {
var handler = PasswordChange; var handler = PasswordChange;
if (handler != null) if (handler == null) return;
{
var args = new StringChangeEventArgs(value, type); var args = new StringChangeEventArgs(value, type) {Index = index};
args.Index = index; PasswordChange(this, args);
PasswordChange(this, args);
}
} }
#endregion
} }
} }

View file

@ -0,0 +1,54 @@
namespace PepperDash.Core.PasswordManagement
{
/// <summary>
/// Represents the result of a password validation attempt
/// </summary>
public class PasswordValidationResult
{
/// <summary>
/// Indicates whether the validation was successful
/// </summary>
public bool IsValid { get; private set; }
/// <summary>
/// Password
/// </summary>
public string Password { get; private set; }
/// <summary>
/// Message describing the validation result
/// </summary>
public string Message { get; private set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="isValid">Whether the validation was successful</param>
/// <param name="message">Message describing the result</param>
/// <param name="password"></param>
public PasswordValidationResult(bool isValid, string message, string password)
{
IsValid = isValid;
Message = message;
Password = password;
}
/// <summary>
/// Creates a successful validation result
/// </summary>
/// <param name="message">The success message</param>
public static PasswordValidationResult Success(string message, string password)
{
return new PasswordValidationResult(true, message, password);
}
/// <summary>
/// Creates a failed validation result with the specified message
/// </summary>
/// <param name="message">The failure reason</param>
public static PasswordValidationResult Failure(string message)
{
return new PasswordValidationResult(false, message, null);
}
}
}

View file

@ -0,0 +1,247 @@
[BEGIN]
Version=1
[END]
[BEGIN]
ObjTp=FSgntr
Sgntr=UserSPlus
RelVrs=1
IntStrVrs=1
SPlusVrs=4.06.00
CrossCplrVrs=1.3
[END]
[BEGIN]
ObjTp=Hd
IncludePath1=..\bin
Cmn1=INPUTS\\--------------------------------------------------------
Cmn2=-----\\Debug (d) \\- enables/disables debugging of password client||1
Cmn3=class\\\\Initialize (d) - REMOVED\\- Clients are automatically initialized||1
Cmn4=via event subscription with the Manager\\\\PasswordValidate (d)||1
Cmn5=*Optional\\- Triggers validate method, the module will automatically||1
Cmn6=trigger the \\ validate method when the entered password equals||1
Cmn7=the length of the \\ selected password\\ \\Keypad (d)\\- Used||1
Cmn8=for basic numeric pins\\\\PasswordSelect[1-10] (d)\\- Allows developer||1
Cmn9=to select different passwords used for validation\\\\PasswordSelectByIndex||1
Cmn10=(a)\\- Alternate method for selecting password used for validation\\
Cmn11=\\PasswordtoValidate (s)\\- Allows developer to supply raw alpha-
Cmn12=numeric text as the password \\ to validate. Typically fed from||1
Cmn13=a keyboard raw output\\ \\OUTPUTS\\----------------------------
Cmn14=---------------------------------\\InitializedFb (d)\\- Feedback||1
Cmn15=the client is initialized\\\\PasswordIsValid (d) *Pulse\\- Pulses||1
Cmn16=when the password entered (pin or raw text) is valid\\\\PasswordIsInvalid||1
Cmn17=(d) *Pulse\\- Pulses when the password entered (pin or raw text)||1
Cmn18=is not valid\\\\PasswordLedFb[1-10] (d)\\- Remains high while the||1
Cmn19=entered password length matches the LED length\\\\PasswordSelectedIndex||1
Cmn20=(a)\\- Feedback of the selected password\\\\PasswordSelectedLength||1
Cmn21=(a)\\- Feedback of the selected password length. Typically drives||1
Cmn22=the LED\\ SRL analog input 'Set Number of Items'\\ \\PasswordToValidateLength||1
Cmn23=(a)\\- Analog feedback of characters entered by user
[END]
[BEGIN]
ObjTp=Symbol
Exclusions=1,19,20,21,88,89,167,168,179,213,214,215,216,217,225,226,248,249,266,267,310,362,378,380,405,407,408,409,478,522,537,554,586,590,611,624,718,756,767,830,841,842,854,883,955,1032,1062,1079,1128,1129,1134,1140,1157,1158,1195,1199,1220,1221,1222,1223,1299,1348,1349,1439,1472,1473,1499,1746,1803,1975,2229,2354,2514,2523,2532,2706,2707,3235,3236,3427,3454,3567,3568,3601,3602,3708,3902,3903,3912,3918,3925,3926,4206,4207,
Exclusions_CDS=5
Inclusions_CDS=6,7
Name=PepperDash_Core_Password_Client_A4sA3s_v02.00
SmplCName=PepperDash_Core_Password_Client_A4sA3s_v02.00.usp
Code=1
SysRev5=4.006
SMWRev=3.00.00
InputCue1=[~UNUSED~]
InputSigType1=Digital
InputCue2=[~UNUSED~]
InputSigType2=Digital
InputCue3=[~UNUSED~]
InputSigType3=Digital
InputCue4=DebugEnable
InputSigType4=Digital
InputCue5=[~UNUSED~]
InputSigType5=Digital
InputCue6=[~UNUSED~]
InputSigType6=Digital
InputCue7=ValidateUsername
InputSigType7=Digital
InputCue8=ValidatePassword
InputSigType8=Digital
InputCue9=[~UNUSED~]
InputSigType9=Digital
InputCue10=KeypadClear
InputSigType10=Digital
InputCue11=KeypadBackspace
InputSigType11=Digital
InputCue12=Keypad00
InputSigType12=Digital
InputCue13=Keypad01
InputSigType13=Digital
InputCue14=Keypad02
InputSigType14=Digital
InputCue15=Keypad03
InputSigType15=Digital
InputCue16=Keypad04
InputSigType16=Digital
InputCue17=Keypad05
InputSigType17=Digital
InputCue18=Keypad06
InputSigType18=Digital
InputCue19=Keypad07
InputSigType19=Digital
InputCue20=Keypad08
InputSigType20=Digital
InputCue21=Keypad09
InputSigType21=Digital
OutputCue1=[~UNUSED~]
OutputSigType1=Digital
OutputCue2=[~UNUSED~]
OutputSigType2=Digital
OutputCue3=[~UNUSED~]
OutputSigType3=Digital
OutputCue4=[~UNUSED~]
OutputSigType4=Digital
OutputCue5=InitializedFb
OutputSigType5=Digital
OutputCue6=[~UNUSED~]
OutputSigType6=Digital
OutputCue7=UsernameIsValid
OutputSigType7=Digital
OutputCue8=UsernameIsInvalid
OutputSigType8=Digital
OutputCue9=[~UNUSED~]
OutputSigType9=Digital
OutputCue10=PasswordIsValid
OutputSigType10=Digital
OutputCue11=PasswordIsInvalid
OutputSigType11=Digital
OutputCue12=[~UNUSED~]
OutputSigType12=Digital
OutputCue13=PasswordLedFb[#]
OutputSigType13=Digital
InputList2Cue1=[~UNUSED~]
InputList2SigType1=Serial
InputList2Cue2=[~UNUSED~]
InputList2SigType2=Serial
InputList2Cue3=[~UNUSED~]
InputList2SigType3=Serial
InputList2Cue4=[~UNUSED~]
InputList2SigType4=Serial
InputList2Cue5=[~UNUSED~]
InputList2SigType5=Serial
InputList2Cue6=Username
InputList2SigType6=Serial
InputList2Cue7=Password
InputList2SigType7=Serial
OutputList2Cue1=[~UNUSED~]
OutputList2SigType1=Analog
OutputList2Cue2=PasswordSelectedLength
OutputList2SigType2=Analog
OutputList2Cue3=PasswordToValidateLength
OutputList2SigType3=Analog
OutputList2Cue4=[~UNUSED~]
OutputList2SigType4=Serial
OutputList2Cue5=UsernameFb
OutputList2SigType5=Serial
OutputList2Cue6=MessageFb
OutputList2SigType6=Serial
ParamCue1=[Reference Name]
ParamCue2=ValidatePulseLength
ParamSigType2=Constant
ParamCue3=ValidateUsernameOnChange,0d,1d
ParamSigType3=List
ParamCue4=ValidatePasswordOnChange,0d,1d
ParamSigType4=List
MinVariableInputs=21
MaxVariableInputs=21
MinVariableInputsList2=7
MaxVariableInputsList2=7
MinVariableOutputs=22
MaxVariableOutputs=22
MinVariableOutputsList2=6
MaxVariableOutputsList2=6
MinVariableParams=3
MaxVariableParams=3
Expand=expand_separately
Expand2=expand_inputs_with_outputs
ProgramTree=Logic
SymbolTree=46
UserSymTreeName=PepperDash Technology
Hint=
PdfHelp=
HelpID=
Render=4
Smpl-C=16
CompilerCode=-48
CompilerParamCode=27
CompilerParamCode5=14
NumFixedParams=1
Pp1=1
Pp2=2
Pp3=3
Pp4=4
MPp=4
NVStorage=10
ParamSigType1=String
SmplCInputCue1=o#
SmplCOutputCue1=i#
SmplCInputList2Cue1=an#
SmplCOutputList2Cue1=ai#
SPlus2CompiledName=S2_PepperDash_Core_Password_Client_A4sA3s_v02_00
SymJam=NonExclusive
FileName=PepperDash_Core_Password_Client_A4sA3s_v02.00.ush
SIMPLPlusModuleEncoding=0
clz1=PepperDash_Core
[END]
[BEGIN]
ObjTp=Dp
H=1
Tp=1
NoS=False
[END]
[BEGIN]
ObjTp=Dp
H=2
Tp=1
HD=True
DV=500d
Sgn=0
Lng=False
NF=1
NoS=True
DNF=1
VVS=1
LR=50d
HR=1000d
[END]
[BEGIN]
ObjTp=Dp
H=3
Tp=1
HD=True
DV=0d
Sgn=0
Lng=False
NF=1
NoS=True
DNF=1
VVS=2
VN=2
Val1=0d
Lbl1=False
Val2=1d
Lbl2=True
[END]
[BEGIN]
ObjTp=Dp
H=4
Tp=1
HD=True
DV=0d
Sgn=0
Lng=False
NF=1
NoS=True
DNF=1
VVS=2
VN=2
Val1=0d
Lbl1=False
Val2=1d
Lbl2=True
[END]

View file

@ -0,0 +1,389 @@
/*******************************************************************************************
Dealer Name: PepperDash Technology Corp.
Programmer: PepperDash Technology Corp.
Copyright: 2018
********************************************************************************************
Notice of Ownership and Copyright
The material in which this notice appears is the property of PepperDash Technology Corporation,
which claims copyright under the laws of the United States of America in the entire body of
material and in all parts thereof, regardless of the use to which it is being put. Any use,
in whole or in part, of this material by another party without the express written permission
of PepperDash Technology Corporation is prohibited.
PepperDash Technology Corporation reserves all rights under applicable laws.
*******************************************************************************************/
/*******************************************************************************************
Compiler Directives
(Uncomment and declare compiler directives as needed)
*******************************************************************************************/
#CATEGORY "46" "PepperDash Technology"
#DEFAULT_VOLATILE
#ENABLE_STACK_CHECKING
#ENABLE_TRACE
#ANALOG_SERIAL_EXPAND InputsWithOutputs
#DEFINE_CONSTANT MAX_LEN_SYMBOL 50
#DEFINE_CONSTANT MAX_LEN_MSG 200
#DEFINE_CONSTANT MAX_LEN_STR 250
#DEFINE_CONSTANT MAX_LEN_PULSE 50
#DEFINE_CONSTANT MAX_PASSWORDS 10
#DEFINE_CONSTANT MAX_LEDS 10
#DEFINE_CONSTANT ENUM_TYPE_NONE 0
#DEFINE_CONSTANT ENUM_TYPE_BACKDOOR 1
#DEFINE_CONSTANT ENUM_TYPE_GLOBAL 2
#DEFINE_CONSTANT ENUM_TYPE_SYSTEM 3
#DEFINE_CONSTANT ENUM_TYPE_ROOM 4
#DEFINE_CONSTANT ENUM_TYPE_TECH 5
#DEFINE_CONSTANT ENUM_TYPE_USER 6
#HELP_BEGIN
INPUTS
-------------------------------------------------------------
Debug (d)
- enables/disables debugging of password client class
Initialize (d) - REMOVED
- Clients are automatically initialized via event subscription with the Manager
PasswordValidate (d) *Optional
- Triggers validate method, the module will automatically trigger the
validate method when the entered password equals the length of the
selected password
Keypad (d)
- Used for basic numeric pins
PasswordSelect[1-10] (d)
- Allows developer to select different passwords used for validation
PasswordSelectByIndex (a)
- Alternate method for selecting password used for validation
PasswordtoValidate (s)
- Allows developer to supply raw alpha-numeric text as the password
to validate. Typically fed from a keyboard raw output
OUTPUTS
-------------------------------------------------------------
InitializedFb (d)
- Feedback the client is initialized
PasswordIsValid (d) *Pulse
- Pulses when the password entered (pin or raw text) is valid
PasswordIsInvalid (d) *Pulse
- Pulses when the password entered (pin or raw text) is not valid
PasswordLedFb[1-10] (d)
- Remains high while the entered password length matches the LED length
PasswordSelectedIndex (a)
- Feedback of the selected password
PasswordSelectedLength (a)
- Feedback of the selected password length. Typically drives the LED
SRL analog input 'Set Number of Items'
PasswordToValidateLength (a)
- Analog feedback of characters entered by user
#HELP_END
/*******************************************************************************************
Include Libraries
(Uncomment and include additional libraries as needed)
*******************************************************************************************/
// comment out or remove when PepperDash_Core.clz is local to the module
#INCLUDEPATH "..\bin"
#USER_SIMPLSHARP_LIBRARY "PepperDash_Core"
/*******************************************************************************************
DIGITAL, ANALOG and SERIAL INPUTS and OUTPUTS
(Uncomment and declare inputs and outputs as needed)
*******************************************************************************************/
DIGITAL_INPUT
_SKIP_,
_SKIP_,
_SKIP_,
DebugEnable,
_SKIP_,
_SKIP_,
ValidateUsername,
ValidatePassword,
_SKIP_,
KeypadClear,
KeypadBackspace,
Keypad00,
Keypad01,
Keypad02,
Keypad03,
Keypad04,
Keypad05,
Keypad06,
Keypad07,
Keypad08,
Keypad09;
STRING_INPUT
_SKIP_,
_SKIP_,
_SKIP_,
_SKIP_,
_SKIP_,
Username[MAX_LEN_STR],
Password[MAX_LEN_STR];
DIGITAL_OUTPUT
_SKIP_,
_SKIP_,
_SKIP_,
_SKIP_,
InitializedFb,
_SKIP_,
UsernameIsValid,
UsernameIsInvalid,
_SKIP_,
PasswordIsValid,
PasswordIsInvalid;
ANALOG_OUTPUT
_SKIP_,
PasswordSelectedLength,
PasswordToValidateLength;
STRING_OUTPUT
_SKIP_,
UsernameFb,
MessageFb;
DIGITAL_OUTPUT
_SKIP_,
PasswordLedFb[MAX_LEDS, MAX_LEDS];
/*******************************************************************************************
SIMPL # Class to be instantiated
*******************************************************************************************/
PasswordClient thisClient;
/*******************************************************************************************
Parameters
(Uncomment and declare parameters as needed)
*******************************************************************************************/
INTEGER_PARAMETER
ValidatePulseLength,
ValidateUsernameOnChange,
ValidatePasswordOnChange;
/*******************************************************************************************
Parameter Properties
(Uncomment and declare parameter properties as needed)
*******************************************************************************************/
#BEGIN_PARAMETER_PROPERTIES ValidatePulseLength
propValidUnits = unitDecimal;
propBounds = 50d, 1000d;
propDefaultValue = 500d;
#END_PARAMETER_PROPERTIES
#BEGIN_PARAMETER_PROPERTIES ValidateUsernameOnChange
propValidUnits = unitDecimal;
propDefaultValue = 0d;
propList = { 0d, "False" }, { 1d, "True" };
#END_PARAMETER_PROPERTIES
#BEGIN_PARAMETER_PROPERTIES ValidatePasswordOnChange
propValidUnits = unitDecimal;
propDefaultValue = 0d;
propList = { 0d, "False" }, { 1d, "True" };
#END_PARAMETER_PROPERTIES
/*******************************************************************************************
Structure Definitions
(Uncomment and define structure definitions as needed)
Note: Be sure to initialize all declared STRING variables as needed
For example, in Function Main: struct.myString = "";
*******************************************************************************************/
/*******************************************************************************************
Global Variables
(Uncomment and declare global variables as needed)
Note: Be sure to initialize all declared STRING variables as needed
For example, in Function Main: myString = "";
*******************************************************************************************/
String
strUsername[MAX_LEN_STR],
strPassword[MAX_LEN_STR];
/*******************************************************************************************
Functions
(Add any additional functions here)
Note: Functions must be physically placed before the location in
the code that calls them.
*******************************************************************************************/
EventHandler BoolChanged(PasswordClient sender, BoolChangeEventArgs args)
{
Switch(args.Type)
{
Case(PasswordConstants.BoolValueChange):
{
// generic bool change
}
Case(PasswordConstants.Initialized):
{
InitializedFb = args.IntValue;
}
Case(PasswordConstants.UsernameValidated):
{
If(args.IntValue = 1)
{
Pulse(ValidatePulseLength, UsernameIsValid);
strPassword = "";
}
Else
{
Pulse(ValidatePulseLength, UsernameIsInvalid);
strUsername = "";
strPassword = "";
}
}
Case(PasswordConstants.PasswordValidated):
{
If(args.IntValue = 1)
{
Pulse(ValidatePulseLength, PasswordIsValid);
strUsername = "";
strPassword = "";
}
Else
{
Pulse(ValidatePulseLength, PasswordIsInvalid);
//strUsername = "";
strPassword = "";
}
}
Case(PasswordConstants.LedFeedback):
{
If(DebugEnable) Trace("LedFeedback: Type[%u] Index[%u] IntValue[%u]\r", args.Type, args.Index, args.IntValue);
If(args.Index = 0)
SetArray(PasswordLedFb, 0);
Else
{
PasswordToValidateLength = args.Index;
PasswordLedFb[args.Index] = args.IntValue;
}
}
Default:
{
If(DebugEnable) Trace("BoolChanged: args[%u].Type[%u] = %u\r", args.Index, args.Type, args.IntValue);
}
}
}
EventHandler UshrtChanged(PasswordClient sender, UshrtChangeEventArgs args)
{
Switch(args.Type)
{
Case(PasswordConstants.UshrtValueChange):
{
// generic ushort change
}
Case(PasswordConstants.PasswordLength):
{
PasswordSelectedLength = args.IntValue;
}
Default:
{
If(DebugEnable) Trace("UshortChanged: args[%u].Type[%u] = %u\r", args.Index, args.Type, args.IntValue);
}
}
}
EventHandler StringChanged(PasswordClient sender, StringChangeEventArgs args)
{
Switch(args.Type)
{
Case(PasswordConstants.StringValueChange):
{
// generic string change
}
Case(PasswordConstants.UsernameValidated):
{
UsernameFb = args.StringValue;
}
Case(PasswordConstants.Message):
{
MessageFb = args.StringValue;
}
Default:
{
If(DebugEnable) Trace("StringChanged: args[%u].Type[%u] = %s\r", args.Index, args.Type, args.StringValue);
}
}
}
/*******************************************************************************************
Event Handlers
(Uncomment and declare additional event handlers as needed)
*******************************************************************************************/
Threadsafe Change Username
{
strUsername = Username;
If(ValidateUsernameOnChange)
{
thisClient.ValidateUsername(strUsername);
}
}
Threadsafe Change Password
{
strPassword = Password;
If(ValidatePasswordOnChange)
{
thisClient.ValidateUsernameAndPassword(strUsername, strPassword);
}
}
Push ValidateUsername
{
thisClient.ValidateUsername(strUsername);
}
Push ValidatePassword
{
thisClient.ValidateUsernameAndPassword(strUsername, strPassword);
}
Push Keypad00 { thisClient.BuildPassword("0"); }
Push Keypad01 { thisClient.BuildPassword("1"); }
Push Keypad02 { thisClient.BuildPassword("2"); }
Push Keypad03 { thisClient.BuildPassword("3"); }
Push Keypad04 { thisClient.BuildPassword("4"); }
Push Keypad05 { thisClient.BuildPassword("5"); }
Push Keypad06 { thisClient.BuildPassword("6"); }
Push Keypad07 { thisClient.BuildPassword("7"); }
Push Keypad08 { thisClient.BuildPassword("8"); }
Push Keypad09 { thisClient.BuildPassword("9"); }
Push KeypadClear { thisClient.ClearPassword(); }
Push KeypadBackspace { thisClient.DeletePasswordCharacter(); }
/*******************************************************************************************
Main()
Uncomment and place one-time startup code here
(This code will get called when the system starts up)
*******************************************************************************************/
Function Main()
{
WaitForInitializationComplete();
RegisterEvent(thisClient, BoolChange, BoolChanged);
RegisterEvent(thisClient, UshrtChange, UshrtChanged);
RegisterEvent(thisClient, StringChange, StringChanged);
}

View file

@ -0,0 +1,134 @@
[BEGIN]
Version=1
[END]
[BEGIN]
ObjTp=FSgntr
Sgntr=UserSPlus
RelVrs=1
IntStrVrs=1
SPlusVrs=4.06.00
CrossCplrVrs=1.3
[END]
[BEGIN]
ObjTp=Hd
IncludePath1=..\bin
Cmn1=INPUTS\\--------------------------------------------------------
Cmn2=-------------\\DebugEnable (d)\\- Enables/disables debug of the||1
Cmn3=password manager class\\\\Initialize (d)\\- Initializes the password||1
Cmn4=manager class\\\\ListPassword (d)\\- Prints the configured passwords||1
Cmn5=to console\\\\PasswordUpdate[1-10] (s)\\- Accepts alpha-numeric||1
Cmn6=pins/passwords that will be used\\ to validate clients against\\
Cmn7=- These values can be driven statically from code (msend/sio), from||1
Cmn8=config,\\ or from Fusion custom propeties.\\\\ \\OUTPUTS\\---
Cmn9=----------------------------------------------------------------
Cmn10=--\\InitializeFb (d)\\- Password manager class initialized feedback\\
Cmn11=\\PasswordCout (a)\\- Analog feedback of current number of passwords||1
Cmn12=configured\\\\Username\\- Can be an alpha-numeric username OR will||1
Cmn13=become the index represented as a sring\\\\Password\\- Passowrd||1
Cmn14=for the username||1
[END]
[BEGIN]
ObjTp=Symbol
Exclusions=1,19,20,21,88,89,167,168,179,213,214,215,216,217,225,226,248,249,266,267,310,362,378,380,405,407,408,409,478,522,537,554,586,590,611,624,718,756,767,830,841,842,854,883,955,1032,1062,1079,1128,1129,1134,1140,1157,1158,1195,1199,1220,1221,1222,1223,1299,1348,1349,1439,1472,1473,1499,1746,1803,1975,2229,2354,2514,2523,2532,2706,2707,3235,3236,3427,3454,3567,3568,3601,3602,3708,3902,3903,3912,3918,3925,3926,4206,4207,
Exclusions_CDS=5
Inclusions_CDS=6,7
Name=PepperDash_Core_Password_Manager_A4sA3s_v02.00
SmplCName=PepperDash_Core_Password_Manager_A4sA3s_v02.00.usp
Code=1
SysRev5=4.006
SMWRev=3.00.00
InputCue1=[~UNUSED~]
InputSigType1=Digital
InputCue2=DebugEnable
InputSigType2=Digital
InputCue3=Initialize
InputSigType3=Digital
InputCue4=[~UNUSED~]
InputSigType4=Digital
InputCue5=ListEntries
InputSigType5=Digital
OutputCue1=[~UNUSED~]
OutputSigType1=Digital
OutputCue2=[~UNUSED~]
OutputSigType2=Digital
OutputCue3=InitializedFb
OutputSigType3=Digital
OutputCue4=[~UNUSED~]
OutputSigType4=Digital
OutputCue5=[~UNUSED~]
OutputSigType5=Digital
InputList2Cue1=[~UNUSED~]
InputList2SigType1=Serial
InputList2Cue2=Username[1]
InputList2SigType2=Serial
InputList2Cue3=Username[2]
InputList2SigType3=Serial
InputList2Cue4=Username[3]
InputList2SigType4=Serial
InputList2Cue5=Username[4]
InputList2SigType5=Serial
InputList2Cue6=Username[5]
InputList2SigType6=Serial
InputList2Cue7=Username[6]
InputList2SigType7=Serial
InputList2Cue8=Username[7]
InputList2SigType8=Serial
InputList2Cue9=Username[8]
InputList2SigType9=Serial
InputList2Cue10=Username[9]
InputList2SigType10=Serial
InputList2Cue11=Username[10]
InputList2SigType11=Serial
InputList2Cue12=[~UNUSED~]
InputList2SigType12=Serial
InputList2Cue13=Password[#]
InputList2SigType13=Serial
OutputList2Cue1=[~UNUSED~]
OutputList2SigType1=Analog
OutputList2Cue2=PasswordCount
OutputList2SigType2=Analog
ParamCue1=[Reference Name]
MinVariableInputs=5
MaxVariableInputs=5
MinVariableInputsList2=22
MaxVariableInputsList2=22
MinVariableOutputs=5
MaxVariableOutputs=5
MinVariableOutputsList2=2
MaxVariableOutputsList2=2
MinVariableParams=0
MaxVariableParams=0
Expand=expand_inputs_with_outputs
Expand2=expand_inputs_with_outputs
ProgramTree=Logic
SymbolTree=46
UserSymTreeName=PepperDash Technology
Hint=
PdfHelp=
HelpID=
Render=4
Smpl-C=16
CompilerCode=-48
CompilerParamCode=27
CompilerParamCode5=14
NumFixedParams=1
Pp1=1
MPp=1
NVStorage=10
ParamSigType1=String
SmplCInputCue1=o#
SmplCOutputCue1=i#
SmplCInputList2Cue1=an#
SmplCOutputList2Cue1=ai#
SPlus2CompiledName=S2_PepperDash_Core_Password_Manager_A4sA3s_v02_00
SymJam=NonExclusive
FileName=PepperDash_Core_Password_Manager_A4sA3s_v02.00.ush
SIMPLPlusModuleEncoding=0
clz1=PepperDash_Core
[END]
[BEGIN]
ObjTp=Dp
H=1
Tp=1
NoS=False
[END]

View file

@ -0,0 +1,257 @@
/*******************************************************************************************
Dealer Name: PepperDash Technology Corp.
Programmer: PepperDash Technology Corp.
Copyright: 2026
********************************************************************************************
Notice of Ownership and Copyright
The material in which this notice appears is the property of PepperDash Technology Corporation,
which claims copyright under the laws of the United States of America in the entire body of
material and in all parts thereof, regardless of the use to which it is being put. Any use,
in whole or in part, of this material by another party without the express written permission
of PepperDash Technology Corporation is prohibited.
PepperDash Technology Corporation reserves all rights under applicable laws.
*******************************************************************************************/
/*******************************************************************************************
Compiler Directives
(Uncomment and declare compiler directives as needed)
*******************************************************************************************/
#CATEGORY "46" "PepperDash Technology"
#DEFAULT_VOLATILE
#ENABLE_STACK_CHECKING
#ENABLE_TRACE
#DIGITAL_EXPAND InputsWithOutputs
#ANALOG_SERIAL_EXPAND InputsWithOutputs
#DEFINE_CONSTANT MAX_LEN_SYMBOL 50
#DEFINE_CONSTANT MAX_LEN_MSG 200
#DEFINE_CONSTANT MAX_LEN_STR 250
#DEFINE_CONSTANT MAX_PASSWORDS 10
#HELP_BEGIN
INPUTS
---------------------------------------------------------------------
DebugEnable (d)
- Enables/disables debug of the password manager class
Initialize (d)
- Initializes the password manager class
ListPassword (d)
- Prints the configured passwords to console
PasswordUpdate[1-10] (s)
- Accepts alpha-numeric pins/passwords that will be used
to validate clients against
- These values can be driven statically from code (msend/sio), from config,
or from Fusion custom propeties.
OUTPUTS
---------------------------------------------------------------------
InitializeFb (d)
- Password manager class initialized feedback
PasswordCout (a)
- Analog feedback of current number of passwords configured
#HELP_END
/*******************************************************************************************
Include Libraries
(Uncomment and include additional libraries as needed)
*******************************************************************************************/
// comment out or remove when PepperDash_Core.clz is local to the module
#INCLUDEPATH "..\bin"
#USER_SIMPLSHARP_LIBRARY "PepperDash_Core"
/*******************************************************************************************
DIGITAL, ANALOG and SERIAL INPUTS and OUTPUTS
(Uncomment and declare inputs and outputs as needed)
*******************************************************************************************/
DIGITAL_INPUT
_SKIP_,
DebugEnable,
Initialize,
_SKIP_,
ListEntries;
STRING_INPUT
_SKIP_,
Username[MAX_PASSWORDS][MAX_LEN_STR],
_SKIP_,
Password[MAX_PASSWORDS,MAX_PASSWORDS][MAX_LEN_STR];
DIGITAL_OUTPUT
_SKIP_,
_SKIP_,
InitializedFb,
_SKIP_,
_SKIP_;
ANALOG_OUTPUT
_SKIP_,
PasswordCount;
#HELP_BEGIN
Username
- Can be an alpha-numeric username OR will become the index represented as a sring
Password
- Passowrd for the username
#HELP_END
/*******************************************************************************************
SIMPL # Class to be instantiated
*******************************************************************************************/
PasswordManager thisManager;
/*******************************************************************************************
Parameters
(Uncomment and declare parameters as needed)
*******************************************************************************************/
/*******************************************************************************************
Parameter Properties
(Uncomment and declare parameter properties as needed)
*******************************************************************************************/
/*******************************************************************************************
Structure Definitions
(Uncomment and define structure definitions as needed)
Note: Be sure to initialize all declared STRING variables as needed
For example, in Function Main: struct.myString = "";
*******************************************************************************************/
/*******************************************************************************************
Global Variables
(Uncomment and declare global variables as needed)
Note: Be sure to initialize all declared STRING variables as needed
For example, in Function Main: myString = "";
*******************************************************************************************/
/*******************************************************************************************
Functions
(Add any additional functions here)
Note: Functions must be physically placed before the location in
the code that calls them.
*******************************************************************************************/
Function UpdatePassword(Integer nKey)
{
String un[MAX_LEN_STR];
If(Len(Username[nKey]) = 0)
{
un = ItoA(nKey);
}
Else
{
un = Username[nKey];
}
thisManager.UpdatePassword(un, Password[nKey]);
}
EventHandler BoolChanged(PasswordManager sender, BoolChangeEventArgs args)
{
Integer i;
Switch(args.Type)
{
Case(PasswordConstants.BoolValueChange):
{
// generic bool change
}
Case(PasswordConstants.Initialized):
{
InitializedFb = args.IntValue;
If(InitializedFb)
{
For(i = 1 To MAX_PASSWORDS)
{
UpdatePassword(i);
}
}
}
Case(PasswordConstants.UpdateBusy):
{
If(DebugEnable) Trace("UpdateBusy: args[%u].Type[%u] = %u\r", args.Index, args.Type, args.IntValue);
}
Default:
{
If(DebugEnable) Trace("BoolChanged: args[%u].Type[%u] = %u\r", args.Index, args.Type, args.IntValue);
}
}
}
EventHandler UshrtChanged(PasswordManager sender, UshrtChangeEventArgs args)
{
Switch(args.Type)
{
Case(PasswordConstants.UshrtValueChange):
{
// generic ushort change
}
Case(PasswordConstants.Count):
{
PasswordCount = args.IntValue;
}
Default:
{
If(DebugEnable) Trace("UshortChanged: args[%u].Type[%u] = %u\r", args.Index, args.Type, args.IntValue);
}
}
}
EventHandler StringChanged(PasswordManager sender, StringChangeEventArgs args)
{
Switch(args.Type)
{
Case(PasswordConstants.StringValueChange):
{
// generic string change
}
Default:
{
If(DebugEnable) Trace("StringChanged: args[%u].Type[%u] = %s\r", args.Index, args.Type, args.StringValue);
}
}
}
/*******************************************************************************************
Event Handlers
(Uncomment and declare additional event handlers as needed)
*******************************************************************************************/
Push Initialize
{
If(InitializedFb)
Return;
thisManager.Initialize();
}
Push ListEntries
{
thisManager.ListEntries();
}
Threadsafe Change Password
{
If(InitializedFb)
UpdatePassword(GetLastModifiedArrayIndex());
}
/*******************************************************************************************
Main()
Uncomment and place one-time startup code here
(This code will get called when the system starts up)
*******************************************************************************************/
Function Main()
{
RegisterEvent(thisManager, BoolChange, BoolChanged);
RegisterEvent(thisManager, UshrtChange, UshrtChanged);
RegisterEvent(thisManager, StringChange, StringChanged);
WaitForInitializationComplete();
}

View file

@ -93,6 +93,7 @@
<Compile Include="Comm\TcpServerConfigObject.cs" /> <Compile Include="Comm\TcpServerConfigObject.cs" />
<Compile Include="Config\PortalConfigReader.cs" /> <Compile Include="Config\PortalConfigReader.cs" />
<Compile Include="CoreInterfaces.cs" /> <Compile Include="CoreInterfaces.cs" />
<Compile Include="PasswordManagement\PasswordValidationResult.cs" />
<Compile Include="Web\RequestHandlers\DefaultRequestHandler.cs" /> <Compile Include="Web\RequestHandlers\DefaultRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\WebApiBaseRequestHandler.cs" /> <Compile Include="Web\RequestHandlers\WebApiBaseRequestHandler.cs" />
<Compile Include="Web\WebApiServer.cs" /> <Compile Include="Web\WebApiServer.cs" />
@ -120,8 +121,8 @@
<Compile Include="JsonToSimpl\JsonToSimplGenericMaster.cs" /> <Compile Include="JsonToSimpl\JsonToSimplGenericMaster.cs" />
<Compile Include="JsonToSimpl\JsonToSimplMaster.cs" /> <Compile Include="JsonToSimpl\JsonToSimplMaster.cs" />
<Compile Include="Network\DiscoveryThings.cs" /> <Compile Include="Network\DiscoveryThings.cs" />
<Compile Include="PasswordManagement\Config.cs" /> <Compile Include="PasswordManagement\PasswordConfig.cs" />
<Compile Include="PasswordManagement\Constants.cs" /> <Compile Include="PasswordManagement\PasswordConstants.cs" />
<Compile Include="PasswordManagement\PasswordClient.cs" /> <Compile Include="PasswordManagement\PasswordClient.cs" />
<Compile Include="PasswordManagement\PasswordManager.cs" /> <Compile Include="PasswordManagement\PasswordManager.cs" />
<Compile Include="SystemInfo\EventArgs and Constants.cs" /> <Compile Include="SystemInfo\EventArgs and Constants.cs" />