-
Notifications
You must be signed in to change notification settings - Fork 12
/
RcvWaitState.cs
165 lines (155 loc) · 5.98 KB
/
RcvWaitState.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
using System;
using static UniversaLIS.UniversaLIService;
namespace UniversaLIS
{
class RcvWaitState : ILISState
{
// Track the current frame number to ensure that the received frame is correct.
public int ExpectedFrame = 1;
public RcvWaitState(CommFacilitator comm)
{
this.comm = comm;
}
private readonly CommFacilitator comm;
public void RcvInput(string InputString)
{
switch (InputString)
{
case Constants.ACK:
RcvACK();
break;
case Constants.NAK:
RcvNAK();
break;
case Constants.ENQ:
RcvENQ();
break;
case Constants.EOT:
RcvEOT();
break;
default:
RcvData(InputString);
break;
}
}
public void RcvACK()
{
// This shouldn't happen. Ignore it, I guess, and hope the instrument gets its act together.
AppendToLog("ACK received in RcvWait state.");
}
public void RcvData(string InputString)
{
// Compare the frame number and checksum to see whether the frame is good or bad.
bool isFrameGood;
// Compare frame numbers.
if (InputString.TrimStart('\x02').StartsWith(ExpectedFrame.ToString()))
{
isFrameGood = true;
}
else
{
AppendToLog("Frame number is incorrect!");
isFrameGood = false;
}
// Check checksum.
if (isFrameGood)
{
isFrameGood = CheckChecksum(InputString);
}
// If it's a header message, check the password.
if (isFrameGood)
{
isFrameGood = CheckPassword(InputString);
}
// If the frame is still good after all those checks,
// take appropriate action.
if (isFrameGood)
{
// Send ACK
comm.Send(Constants.ACK);
// Reset rcvTimer to 30 seconds.
comm.RcvTimer.Reset(30);
// Increment frame number.
ExpectedFrame = ++ExpectedFrame % 8;
// Actually handle the frame.
comm.ParseMessageLine(InputString);
}
else
{
// Send NAK
comm.Send(Constants.NAK);
// Reset rcvTimer to 30 seconds.
comm.RcvTimer.Reset(30);
}
}
private bool CheckPassword(string inputString)
{
if (inputString.Substring(0, 3) == $"{Constants.STX}1H")
{
// 1H|\\^&||{password}|
String[] fieldArray = inputString.Split('|');
if (fieldArray[3] != comm.password)
{
return false;
}
}
return true;
}
private bool CheckChecksum(string InputString)
{
string message = InputString;
// There should be a message ending in a <CR><ETX>, then a checksum, and then a <CR><LF> at the end of the line.
// Find the <ETX>. Any message that reaches this part of the code should have one.
int position = message.IndexOf(Constants.ETX);
if (position < 0)
{
// If no <ETX>, maybe it's an intermediate frame. Check for <ETB>.
position = message.IndexOf(Constants.ETB);
if (position < 0)
{
return false;
}
}
string mainMessage = message.Substring(1, position);
// The checksum is generated by passing everything between the <STX> and the checksum to the CHKSum function below,
// but for some reason the "Result Message" examples in the documentation don't match.
// The other messages do, though, so it's probably fine.
string checkSum = message.Substring(position + 1, 2);
// If the checksum doesn't match, write a <NAK> to the sender.
if (checkSum != CHKSum(mainMessage))
{
return false;
}
// Otherwise, it's good.
return true;
}
public void RcvENQ()
{
// This shouldn't happen since we already received the ENQ that brought us to this state.
// Ignore it, I guess, and hope the instrument finds what it's looking for.
AppendToLog("ENQ received in RcvWait state.");
}
public void RcvEOT()
{
// Discard last incomplete message (if applicable).
if (comm.CurrentMessage.Terminator < 'E')
{
comm.CurrentMessage = new Message(comm);
}
else
{
comm.ProcessMessage(comm.CurrentMessage);
}
}
public void RcvNAK()
{
// This shouldn't happen. Ignore it, I guess, and hope the instrument feels better soon.
AppendToLog("NAK received in RcvWait state.");
}
void ILISState.HaveData()
{
// It doesn't matter if we have data to send. We're receiving right now.
AppendToLog("HaveData called in RcvWait state.");
}
}
}