480 lines
13 KiB
C#
480 lines
13 KiB
C#
using Microsoft.Win32;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.IO.Ports;
|
|
using System.Text;
|
|
using System.Timers;
|
|
using System.Windows.Forms;
|
|
|
|
namespace MeetingClock
|
|
{
|
|
public class MeetingClockManager
|
|
{
|
|
private const string MTC = "MTC";
|
|
|
|
public enum MeetingClockState
|
|
{
|
|
NotInitialized,
|
|
NoComPort,
|
|
Disconnected,
|
|
Connected
|
|
}
|
|
|
|
public MeetingClockState State { get; private set; } = MeetingClockState.NotInitialized;
|
|
public string Version { get; private set; }
|
|
public string Port {
|
|
get
|
|
{
|
|
if (this.serialPort != null && this.serialPort.IsOpen)
|
|
{
|
|
return this.serialPort.PortName;
|
|
}
|
|
return "";
|
|
}
|
|
}
|
|
|
|
public delegate void MeetingClockStateChangeHandler(MeetingClockManager manager, MeetingClockState oldState, MeetingClockState newState);
|
|
public event MeetingClockStateChangeHandler StateChanged;
|
|
|
|
private System.Timers.Timer startTimer;
|
|
private System.Timers.Timer checkTimer;
|
|
private BluetoothManager bluetoothManager;
|
|
private SerialPort serialPort;
|
|
|
|
public MeetingClockManager(BluetoothManager bluetoothManager)
|
|
{
|
|
this.NewSerialPort();
|
|
|
|
this.startTimer = new System.Timers.Timer(1000);
|
|
this.startTimer.AutoReset = false;
|
|
this.startTimer.Elapsed += ConnectTimer_Elapsed;
|
|
|
|
this.checkTimer = new System.Timers.Timer(30000);
|
|
this.checkTimer.AutoReset = false;
|
|
this.checkTimer.Elapsed += CheckTimer_Elapsed;
|
|
this.checkTimer.Start();
|
|
|
|
this.bluetoothManager = bluetoothManager;
|
|
this.bluetoothManager.StateChanged += BluetoothManager_StateChanged;
|
|
}
|
|
|
|
private void NewSerialPort() {
|
|
lock (this) {
|
|
if (this.serialPort != null)
|
|
{
|
|
try
|
|
{
|
|
this.serialPort.Close();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// ignored
|
|
}
|
|
}
|
|
this.serialPort = new SerialPort();
|
|
this.serialPort.BaudRate = 9600;
|
|
this.serialPort.Parity = Parity.None;
|
|
this.serialPort.DataBits = 8;
|
|
this.serialPort.StopBits = StopBits.One;
|
|
this.serialPort.Encoding = Encoding.GetEncoding("iso8859-1");
|
|
this.serialPort.ReadTimeout = 5000;
|
|
this.serialPort.WriteTimeout = 5000;
|
|
}
|
|
}
|
|
|
|
private void BluetoothManager_StateChanged(BluetoothManager manager, BluetoothManager.BluetoothState oldState, BluetoothManager.BluetoothState newState)
|
|
{
|
|
switch (newState)
|
|
{
|
|
case BluetoothManager.BluetoothState.On:
|
|
this.startTimer.Start();
|
|
break;
|
|
default:
|
|
this.Disconnect();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void ConnectTimer_Elapsed(object sender, ElapsedEventArgs e)
|
|
{
|
|
this.Connect();
|
|
}
|
|
|
|
private void Connect()
|
|
{
|
|
lock (this)
|
|
{
|
|
if (this.State == MeetingClockState.Connected && this.serialPort.IsOpen)
|
|
{
|
|
Debug.WriteLine("Meeting clock already connected. Not trying to connect again.");
|
|
return;
|
|
}
|
|
|
|
string[] portNames = SerialPort.GetPortNames();
|
|
if (portNames.Length == 0)
|
|
{
|
|
Debug.WriteLine("No COM ports are available at the moment.");
|
|
this.ChangeState(MeetingClockState.NoComPort);
|
|
return;
|
|
}
|
|
|
|
this.ChangeState(MeetingClockState.Disconnected);
|
|
this.NewSerialPort();
|
|
|
|
foreach (string portName in portNames)
|
|
{
|
|
Debug.WriteLine(String.Format("Trying to connect to {0}", portName));
|
|
try
|
|
{
|
|
this.serialPort.PortName = portName;
|
|
this.serialPort.Open();
|
|
|
|
if (this.Handshake())
|
|
{
|
|
Debug.WriteLine(String.Format("Successfully connected to meeting clock {0} on port {1}", this.Version, portName));
|
|
this.Adjust();
|
|
this.ScrollText("");
|
|
this.NextDate(DateTime.Now.AddMinutes(-5));
|
|
this.ChangeState(MeetingClockState.Connected);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
Debug.WriteLine(String.Format("Failed to connect to meeting clock on port {0}. Invalid Handshake.", portName));
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
Debug.WriteLine(String.Format("Failed to connect to meeting clock on port {0}. {1}", portName, exception.Message));
|
|
}
|
|
|
|
this.Disconnect();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Disconnect()
|
|
{
|
|
lock (this)
|
|
{
|
|
if (this.serialPort.IsOpen)
|
|
{
|
|
Debug.WriteLine(String.Format("Closing connection on port {0}", this.serialPort.PortName));
|
|
try
|
|
{
|
|
this.serialPort.Close();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// ignored
|
|
}
|
|
}
|
|
|
|
this.ChangeState(MeetingClockState.Disconnected);
|
|
this.NewSerialPort();
|
|
}
|
|
}
|
|
|
|
private bool Handshake()
|
|
{
|
|
string rx = this.SendAndReceive(MTC);
|
|
|
|
if (rx == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (rx.StartsWith(MTC))
|
|
{
|
|
this.Version = rx.Substring(MTC.Length).Trim();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void Adjust()
|
|
{
|
|
this.SendAndReceive(String.Format("ADJ {0}", DateTime.Now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss")));
|
|
}
|
|
|
|
private string SendAndReceive(string tx)
|
|
{
|
|
lock (this)
|
|
{
|
|
try
|
|
{
|
|
if (this.serialPort.IsOpen)
|
|
{
|
|
Debug.WriteLine(String.Format(">>> {0}", tx));
|
|
this.serialPort.WriteLine(tx);
|
|
string rx = this.serialPort.ReadLine().Trim();
|
|
Debug.WriteLine(String.Format("<<< {0}", rx));
|
|
return rx;
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
Debug.WriteLine(String.Format("Failed to send/receiv on port {0}. {1}", this.serialPort.PortName, exception.Message));
|
|
this.Disconnect();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private void ChangeState(MeetingClockState newState)
|
|
{
|
|
MeetingClockState oldState = this.State;
|
|
this.State = newState;
|
|
|
|
if (newState != oldState)
|
|
{
|
|
Debug.WriteLine("Meeting Clock state change detected. Old state: {0}, new state {1}.", oldState, newState);
|
|
|
|
if (this.StateChanged != null)
|
|
{
|
|
this.StateChanged(this, oldState, newState);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CheckTimer_Elapsed(object sender, ElapsedEventArgs e)
|
|
{
|
|
if (this.serialPort.IsOpen)
|
|
{
|
|
if (!this.Handshake())
|
|
{
|
|
this.Disconnect();
|
|
}
|
|
}
|
|
else if (this.bluetoothManager.State == BluetoothManager.BluetoothState.On)
|
|
{
|
|
this.Connect();
|
|
}
|
|
|
|
this.checkTimer.Start();
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
this.Disconnect();
|
|
this.checkTimer.Stop();
|
|
this.startTimer.Stop();
|
|
}
|
|
|
|
public int? GetTimeInterval()
|
|
{
|
|
try
|
|
{
|
|
string rx = this.SendAndReceive("GET TI").Substring(7);
|
|
return int.Parse(rx);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void SetTimeInterval(int value)
|
|
{
|
|
try
|
|
{
|
|
this.SendAndReceive("SET TI " + value);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
public int? GetDateInterval()
|
|
{
|
|
try
|
|
{
|
|
string rx = this.SendAndReceive("GET DI").Substring(7);
|
|
return int.Parse(rx);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void SetDateInterval(int value)
|
|
{
|
|
try
|
|
{
|
|
this.SendAndReceive("SET DI " + value);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
public int? GetTemperatureInterval()
|
|
{
|
|
try
|
|
{
|
|
string rx = this.SendAndReceive("GET CI").Substring(7);
|
|
return int.Parse(rx);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
public void SetTemperatureInterval(int value)
|
|
{
|
|
try
|
|
{
|
|
this.SendAndReceive("SET CI " + value);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
public int? GetBrightness()
|
|
{
|
|
try
|
|
{
|
|
string rx = this.SendAndReceive("GET IN").Substring(7);
|
|
return int.Parse(rx);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public int? GetScrollSpeed()
|
|
{
|
|
try
|
|
{
|
|
string rx = this.SendAndReceive("GET SS").Substring(7);
|
|
return int.Parse(rx);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public int? GetScrollWait()
|
|
{
|
|
try
|
|
{
|
|
string rx = this.SendAndReceive("GET SW").Substring(7);
|
|
return int.Parse(rx);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void SetBrightness(int value)
|
|
{
|
|
try
|
|
{
|
|
this.SendAndReceive("SET IN " + value);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
public void SetScrollSpeed(int value)
|
|
{
|
|
try
|
|
{
|
|
this.SendAndReceive("SET SS " + value);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
public void SetScrollWait(int value)
|
|
{
|
|
try
|
|
{
|
|
this.SendAndReceive("SET SW " + value);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
public void ScrollText(string value)
|
|
{
|
|
try
|
|
{
|
|
this.SendAndReceive("SCR " + value);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
public bool? GetDateEnabled()
|
|
{
|
|
try
|
|
{
|
|
string rx = this.SendAndReceive("GET DE").Substring(7);
|
|
return int.Parse(rx) > 0;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void SetDateEnabled(bool value)
|
|
{
|
|
try
|
|
{
|
|
this.SendAndReceive("SET DE " + (value ? "1" : "0"));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
public bool? GetTemperatureEnabled()
|
|
{
|
|
try
|
|
{
|
|
string rx = this.SendAndReceive("GET CE").Substring(7);
|
|
return int.Parse(rx) > 0;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void SetTemperatureEnabled(bool value)
|
|
{
|
|
try
|
|
{
|
|
this.SendAndReceive("SET CE " + (value ? "1" : "0"));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
internal void NextDate(DateTime value)
|
|
{
|
|
try
|
|
{
|
|
this.SendAndReceive("NXT " + value.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss"));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|