-
Notifications
You must be signed in to change notification settings - Fork 1
/
Physical.c
294 lines (266 loc) · 10 KB
/
Physical.c
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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/*------------------------------------------------------------------------------
-- SOURCE FILE: Physical.c - Contains all the OSI "physical layer"
-- functions for the wireless protocol tester.
-- The definitions for the OSI layers
-- have been loosened somewhat, since the purpose
-- is to organize the functions intuitively,
-- rather than pedantically.
--
-- PROGRAM: Dean and the Rockets' Wireless Protocol Testing and Evaluation
-- Facilitator
--
-- FUNCTIONS:
-- DWORD WINAPI PortIOThreadProc(HWND);
-- VOID InitStateInfo(PSTATEINFO);
-- VOID ProcessCommError(HANDLE);
-- VOID ReadFromPort(HWND, PSTATEINFO, OVERLAPPED, DWORD)
--
--
-- DATE: Oct 13, 2010
--
-- REVISIONS: Nov 05, 2010
-- Modified ReadThreadProc to work more appropriately for the RFID
-- reader. Added RequestPacket().
--
-- Nov 29, 2010
-- Renamed ReadThreadProc() to PortIOThreadProc(), and modified it
-- to work more appropriately for the wireless protocol tester.
-- Removed RequestPacket(). Added InitStateInfo().
--
-- DESIGNER: Dean Morin
--
-- PROGRAMMER: Dean Morin, Daniel Wright
--
-- NOTES:
-- Contains physical level functions for the wireless protocol reader.
------------------------------------------------------------------------------*/
#include "Physical.h"
/*------------------------------------------------------------------------------
-- FUNCTION: PortIOThreadProc
--
-- DATE: Oct 13, 2010
--
-- REVISIONS: Nov 05, 2010
-- Modified the function to also listen for a "disconnect" event,
-- and to break in that case. ProcessRead() is now called once a
-- complete packet is confirmed (as opposed to sending the
-- contents of the buffer to ProcessRead() as soon as they arrive).
--
-- Nov 29, 2010
-- Renamed function from ReadThreadProc(). The event handling is
-- from the original function, but the response to each event has
-- changed.
--
-- DESIGNER: Dean Morin
--
-- PROGRAMMER: Dean Morin, Daniel Wright
--
-- INTERFACE: DWORD WINAPI PortIOThreadProc(HWND hWnd)
-- hWnd - the handle to the window
--
-- RETURNS: 0 because threads are required to return a DWORD.
--
-- NOTES:
-- While connected, this thread will loop and wait for characters
-- to arrive at the port, or for a timeout to occur, then call the
-- appropriate function. This function uses overlapped I/O.
------------------------------------------------------------------------------*/
DWORD WINAPI PortIOThreadProc(HWND hWnd) {
OVERLAPPED ol = {0};
DWORD dwEvent = 0;
DWORD dwError = 0;
COMSTAT cs = {0};
HANDLE* hEvents = NULL;
PSTATEINFO psi = NULL;
PWNDDATA pwd = (PWNDDATA) GetWindowLongPtr(hWnd, 0);
if ((ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) {
DISPLAY_ERROR("Error creating event in read thread");
}
hEvents = (HANDLE*) malloc(sizeof(HANDLE) * PORT_IO_EVENTS);
hEvents[0] = CreateEvent(NULL, FALSE, FALSE, TEXT("disconnected"));
hEvents[1] = ol.hEvent;
psi = (PSTATEINFO) malloc(sizeof(STATEINFO));
InitStateInfo(psi);
DL_STATE = psi->iState;
while (pwd->bConnected) {
SetCommMask(pwd->hPort, EV_RXCHAR);
if (!WaitCommEvent(pwd->hPort, &dwEvent, &ol)) {
ProcessCommError(pwd->hPort);
}
dwEvent = WaitForMultipleObjects(PORT_IO_EVENTS, hEvents, FALSE,
psi->dwTimeout);
ClearCommError(pwd->hPort, &dwError, &cs);
if (dwEvent == WAIT_OBJECT_0) {
// the connection was severed
break;
}
else if (dwEvent == WAIT_OBJECT_0 + 1 && cs.cbInQue) {
// data arrived at the port
ReadFromPort(hWnd, psi, ol, cs.cbInQue);
}
else if (dwEvent == WAIT_TIMEOUT) {
// a timeout occured
ProcessTimeout(hWnd, psi);
}
else if (dwEvent == WAIT_FAILED) {
DISPLAY_ERROR("Invalid event occured in the Port I/O thread");
}
ResetEvent(ol.hEvent);
}
if (!PurgeComm(pwd->hPort, PURGE_RXCLEAR)) {
DISPLAY_ERROR("Error purging read buffer");
}
CloseHandle(ol.hEvent);
CloseHandle(hEvents[0]);
free(hEvents);
return 0;
}
/*------------------------------------------------------------------------------
-- FUNCTION: InitStateInfo
--
-- DATE: Nov 29, 2010
--
-- REVISIONS: (Date and Description)
--
-- DESIGNER: Dean Morin
--
-- PROGRAMMER: Dean Morin
--
-- INTERFACE: VOID InitStateInfo(PSTATEINFO psi)
-- psi - contains info about the current state of
-- the communication
--
-- RETURNS: VOID.
--
-- NOTES:
-- Initializes the protocol state info to its default values.
------------------------------------------------------------------------------*/
VOID InitStateInfo (PSTATEINFO psi) {
srand(GetTickCount());
psi->rxSeq = 0;
psi->iState = STATE_IDLE;
psi->itoCount = 0;
psi->dwTimeout = TOR0;
psi->iFailedENQCount = 0;
}
/*------------------------------------------------------------------------------
-- FUNCTION: ReadFromPort
--
-- DATE: Nov 29, 2010
--
-- REVISIONS: (Date and Description)
--
-- DESIGNER: Dean Morin
--
-- PROGRAMMER: Dean Morin
--
-- INTERFACE: VOID ReadFromPort(HWND hWnd, PSTATEINFO psi, OVERLAPPED ol,
-- DWORD cbInQue)
-- hWnd - a handle to the window
-- psi - contains info about the current state of the
-- communication
-- ol - the overlapped structure used to wait for
-- characters at the serial port
-- cbinQue - the number of characters that are at the port
--
-- RETURNS: VOID.
--
-- NOTES:
-- Reads from the serial port and calls ProcessRead(). If
-- ProcessRead() returns a zero, it means that only a partial
-- frame was passed. In that case, it waits for more characters
-- to arrive at the port, then appends these new characters to the
-- the partial frame, and calls ProcessRead() again.
------------------------------------------------------------------------------*/
VOID ReadFromPort(HWND hWnd, PSTATEINFO psi, OVERLAPPED ol, DWORD cbInQue) {
static DWORD dwQueueSize = 0;
PWNDDATA pwd = NULL;
BYTE pReadBuf[READ_BUFSIZE] = {0};
PBYTE pQueue = NULL;
DWORD dwBytesRead = 0;
DWORD i = 0;
pwd = (PWNDDATA) GetWindowLongPtr(hWnd, 0);
if (!ReadFile(pwd->hPort, pReadBuf, READ_BUFSIZE, &dwBytesRead, &ol)) {
// read is incomplete or had an error
ProcessCommError(pwd->hPort);
GetOverlappedResult(pwd->hThread, &ol, &dwBytesRead, TRUE);
}
if (dwQueueSize == 0) {
// the last port read sent an entire frame to ProcessRead()
if (dwBytesRead >= CTRL_FRAME_SIZE &&
ProcessRead(hWnd, psi, pReadBuf, dwBytesRead)) {
// read completed successfully
return;
} else {
// a full frame is not yet at the port
for (i = 0; i < dwBytesRead; i++) {
AddToByteQueue(&pwd->pReadBufHead, &pwd->pReadBufTail, pReadBuf[i]);
dwQueueSize++;
}
if (dwQueueSize != dwBytesRead) {
DISPLAY_ERROR("Port read is out of sync");
}
}
} else {
// the previous port read was not finished
for (i = 0; i < dwBytesRead; i++) {
AddToByteQueue(&pwd->pReadBufHead, &pwd->pReadBufTail, pReadBuf[i]);
dwQueueSize++;
}
// checks for 1 byte read, in case the tx side is out of sync
if (dwQueueSize >= FRAME_SIZE || dwBytesRead == CTRL_FRAME_SIZE) {
pQueue = RemoveFromByteQueue(&pwd->pReadBufHead, dwQueueSize);
ProcessRead(hWnd, psi, pQueue, dwQueueSize);
// read completed successfully
dwQueueSize = 0;
DeleteByteQueue(pwd->pReadBufHead);
pwd->pReadBufHead = NULL;
pwd->pReadBufTail = NULL;
for (i = 0; i < dwQueueSize; i++) {
free(pQueue);
}
}
}
}
/*------------------------------------------------------------------------------
-- FUNCTION: ProcessCommError
--
-- DATE: Oct 13, 2010
--
-- REVISIONS: (Date and Description)
--
-- DESIGNER: Dean Morin
--
-- PROGRAMMER: Dean Morin
--
-- INTERFACE: VOID ProcessCommError(HANDLE hPort)
-- hPort - the handle to the open port
--
-- RETURNS: VOID.
--
-- NOTES:
-- Displays messages for various communication errors. Most of the
-- time, this function will process ERROR_IO_PENDING and return
-- early since this is expected in overlapped I/O.
------------------------------------------------------------------------------*/
VOID ProcessCommError(HANDLE hPort) {
DWORD dwError;
if (GetLastError() == ERROR_IO_PENDING) {
return;
}
ClearCommError(hPort, &dwError, NULL);
switch (dwError) {
case CE_BREAK:
DISPLAY_ERROR("The hardware detected a break condition");
case CE_FRAME:
DISPLAY_ERROR("The hardware detected a framing error");
case CE_OVERRUN:
DISPLAY_ERROR("A character-buffer overrun has occurred. The next character is lost.");
case CE_RXOVER:
DISPLAY_ERROR("An input buffer overflow has occurred. There is either no room in the input buffer, or a character was received after the end-of-file (EOF) character");
case CE_RXPARITY:
DISPLAY_ERROR("The hardware detected a parity error");
default:
DISPLAY_ERROR("A communication error occured");
}
}