-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclsSACommMgr.cs
259 lines (227 loc) · 10.3 KB
/
clsSACommMgr.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace HSPI_ENVIRACOM_MANAGER
{
/// <summary>
///
/// </summary>
public class clsSACommMgr
{
#region " Enumerations and Constants "
private const string LOG_MESSAGES = "enviracom_sa_messages.log";
#endregion
#region " Structures "
struct Message
{
public delegate void ProcessMessageDelegate(string sMsg);
public string text;
public string desc;
public ProcessMessageDelegate proc;
public Message(string sText, string sDesc, ProcessMessageDelegate DoW)
{
text = sText;
desc = sDesc;
proc = DoW;
}
};
#endregion
#region " Members "
private Dictionary<string, Message> m_dctAdapterDictionary = new Dictionary<string, Message>();
private clsEnviracomApp m_objApp = clsEnviracomApp.GetInstance();
private SerialPort m_spComPort = null;
private string m_sComPortName = "COM0";
private bool m_bRunning = false;
private clsHvacController m_objHvacUnit = null;
private Thread m_thrReadThread = null;
private ProcessingQueue<string> m_queTransmitQueue = new ProcessingQueue<string>();
private ProcessingQueue<string> m_queReceiveQueue = new ProcessingQueue<string>();
private EventWaitHandle m_ewhWaitProcess = new EventWaitHandle(false, EventResetMode.AutoReset);
#endregion
#region " Accessor Methods for Members "
public string Port
{
get
{
return m_sComPortName;
}
}
public ProcessingQueue<string>.DoWorkDlgt ReceiveProcessor
{
set
{
m_queReceiveQueue.DoWork += value;
}
}
#endregion
#region " Constructors and Destructors "
public clsSACommMgr()
{
m_dctAdapterDictionary.Add("[Idle]", new Message("[Idle]", "HVAC_IDLE", TraceAdapterMessage));
m_dctAdapterDictionary.Add("[Ack]", new Message("[Ack]", "HVAC_ACK", ReceiveAdapterAckMessage));
m_dctAdapterDictionary.Add("[Nak]", new Message("[Nak]", "HVAC_NAK", TraceAdapterMessage));
m_dctAdapterDictionary.Add("[Reset]", new Message("[Reset]", "HVAC_RESET", TraceAdapterMessage));
}
~clsSACommMgr()
{
}
#endregion
#region " Static Methods "
#endregion
#region " Initialization and Cleanup "
public void Initialize(clsHvacController hvacUnit)
{
// Init members as necessary
try
{
m_objHvacUnit = hvacUnit;
m_sComPortName = m_objHvacUnit.Port;
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, clsEnviracomApp.PLUGIN_IN_NAME_SHORT + ": communications will be on port: " + m_sComPortName.ToString());
}
catch (Exception ex)
{
clsEnviracomApp.TraceEvent(TraceEventType.Critical, "clsSACommMgr::Initialize: Reporting exception: " + ex.ToString());
}
}
public void Cleanup()
{
// Cleanup members and set others to defaults
m_objHvacUnit = null;
m_sComPortName = "";
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "clsSACommMgr::Cleanup called ");
}
public void Startup()
{
// Start listening for data
try
{
m_bRunning = true;
m_spComPort = new SerialPort(m_sComPortName, m_objApp.BaudRate, Parity.None);
m_spComPort.ReadTimeout = m_objApp.MsgTimeOut;
m_spComPort.Open();
m_queTransmitQueue.DoWork += new ProcessingQueue<string>.DoWorkDlgt(OnDoTransmit);
m_thrReadThread = new Thread(ReceiveThread);
m_thrReadThread.IsBackground = true;
m_thrReadThread.Start();
clsEnviracomApp.LogInformation("clsSACommMgr::Startup: Opened COM port: " + m_sComPortName + " for unit: " + m_objHvacUnit.UnitNumber);
}
catch (Exception ex)
{
// This isn't good, log it appropriately
clsEnviracomApp.TraceEvent(TraceEventType.Critical, "clsSACommMgr::Startup: Reporting exception: " + ex.ToString());
}
}
public void Shutdown()
{
// Cleanup some variables, have to wait for a callback to stop listening for the data
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "clsSACommMgr::Shutdown called ");
m_bRunning = false;
m_queTransmitQueue.Stop();
m_queReceiveQueue.Stop();
m_thrReadThread.Join();
m_spComPort.Close();
m_spComPort = null;
}
#endregion
#region " Public Methods "
public void TransmitMessage(string szMessage)
{
m_queTransmitQueue.QueueForWork(szMessage);
}
#endregion
#region " Private Methods "
#region " Private Communications Methods "
private void OnDoTransmit(object sender, ProcessingQueueEventArgs<string> args)
{
string szMessage = args.Work;
try
{
// Make sure we are running before processing
if (m_bRunning)
{
m_spComPort.WriteLine(szMessage + "\r");
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "clsSACommMgr::Transmit: sent message: '" + szMessage + "' on port: " + m_sComPortName.ToString());
if (m_ewhWaitProcess.WaitOne(m_objApp.MsgWaitAck) == true)
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "clsSACommMgr::Transmit: got ack on port: " + m_sComPortName.ToString());
else
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "clsSACommMgr::Transmit: timeout on port: " + m_sComPortName.ToString());
Thread.Sleep(m_objApp.MsgDelay);
}
else
{
// We are no longer running, so just log this attempt and throw away this message
clsEnviracomApp.TraceEvent(TraceEventType.Warning, "clsSACommMgr::Transmit: tried to send message when communications not enabled: '" + szMessage + "' on port: " + m_sComPortName.ToString());
}
}
catch (Exception ex)
{
// This isn't good, log it appropriately
clsEnviracomApp.TraceEvent(TraceEventType.Critical, "clsSACommMgr::Transmit: Reporting exception: " + ex.ToString() + " on port: " + m_sComPortName.ToString());
}
}
private void ReceiveThread()
{
// Make sure we are running before processing
while (m_bRunning)
{
try
{
String receiveBytes = m_spComPort.ReadLine();
// Check if this is adapter message. The adapter messages we are looking
// for start with the string ">[" and end with the string "]\r".
if ((receiveBytes.StartsWith(">[") && receiveBytes.EndsWith("]\r")))
{
Message msg;
string sMessage = receiveBytes.TrimStart('>').TrimEnd('\r');
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "clsSACommMgr::ReceiveThread: read adapter message: '" + receiveBytes.TrimEnd('\r') + "' on port: " + m_sComPortName.ToString());
if (m_dctAdapterDictionary.TryGetValue(sMessage, out msg) == true)
msg.proc(sMessage);
else
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "clsSaCommMgr::ReceiveThread: did not find adapter message '" + sMessage + "' in dictionary");
}
// Check if this is the correct message type. The enviracom messages we are looking
// for start with a '>' and end with a '\r'.
else if (receiveBytes.StartsWith(">") && receiveBytes.EndsWith("\r"))
{
string sMessage = receiveBytes.TrimStart('>').TrimEnd('\r');
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "clsSACommMgr::ReceiveThread: read enviracom message: '" + receiveBytes.TrimEnd('\r') + "' on port: " + m_sComPortName.ToString());
m_queReceiveQueue.QueueForWork(sMessage);
}
else
{
clsEnviracomApp.TraceEvent(TraceEventType.Error, "clsSACommMgr::ReceiveThread: message not formatted correctly: '" + receiveBytes.TrimEnd('\r') + "' on port: " + m_sComPortName.ToString());
}
}
catch (TimeoutException)
{
if (!m_bRunning)
return;
}
catch (Exception ex)
{
clsEnviracomApp.TraceEvent(TraceEventType.Critical, "clsSACommMgr::ReceiveThread: Reporting exception: " + ex.ToString() + " on port: " + m_sComPortName.ToString());
}
}
}
#endregion
#region " Private Internal Methods "
private void TraceAdapterMessage(string sMsg)
{
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "clsSACommMgr::TraceAdapterMessage: message string is '" + sMsg + "'");
}
private void ReceiveAdapterAckMessage(string sMsg)
{
m_ewhWaitProcess.Set();
clsEnviracomApp.TraceEvent(TraceEventType.Verbose, "clsSACommMgr::ReceiveAdapterAckMessage: message string is '" + sMsg + "'");
}
#endregion
#endregion
}
}