source: xtideuniversalbios/trunk/Serial_Server/library/Process.cpp@ 246

Last change on this file since 246 was 233, checked in by gregli@…, 13 years ago

Serial Port: split single byte port and baud into two bytes, taking advantage of the two bytes in DPT_SERIAL, which supports more serial baud rates and in particular fixed a bug where a 4x client machine couldn't talk to a 115.2K server machine. This is a wide change, touching lots of files, but most are shallow changes. DetectPrint.asm took the most significant changes, now it calculates the baud rate to display instead of using characters provided by the Configurator. The Configurator now has a new menu flag, FLG_MENUITEM_CHOICESTRINGS, for specifying that values are not linear and they should be lookedup rather than indexed. Finally, another important bug fixed here is that in some error cases, the serial port code could get into an infinite loop waiting ont the hardware; now it has a timeout.

File size: 9.4 KB
Line 
1//======================================================================
2//
3// Project: XTIDE Universal BIOS, Serial Port Server
4//
5// File: process.cpp - Processes commands received over the serial port
6//
7
8#include "library.h"
9#include <memory.h>
10#include <string.h>
11#include <stdio.h>
12
13union _buff {
14 struct {
15 unsigned char command;
16 unsigned char driveAndHead;
17 unsigned char count;
18 unsigned char sector;
19 unsigned short cylinder;
20 } chs;
21 struct {
22 unsigned char command;
23 unsigned char bits24;
24 unsigned char count;
25 unsigned char bits00;
26 unsigned char bits08;
27 unsigned char bits16;
28 } lba;
29 struct {
30 unsigned char command;
31 unsigned char driveAndHead;
32 unsigned char count;
33 unsigned char scan;
34 unsigned char port;
35 unsigned char baud;
36 } inquire;
37 unsigned char b[514];
38 unsigned short w[257];
39} buff;
40
41#define SERIAL_COMMAND_HEADER 0xa0
42
43#define SERIAL_COMMAND_WRITE 1
44#define SERIAL_COMMAND_READWRITE 2
45#define SERIAL_COMMAND_RWMASK 3
46#define SERIAL_COMMAND_INQUIRE 0
47
48#define SERIAL_COMMAND_MASK 0xe3
49#define SERIAL_COMMAND_HEADERMASK 0xe0
50
51#define ATA_COMMAND_LBA 0x40
52#define ATA_COMMAND_HEADMASK 0xf
53
54#define ATA_DriveAndHead_Drive 0x10
55
56void logBuff( char *message, unsigned long buffoffset, unsigned long readto, int verboseLevel )
57{
58 char logBuff[ 514*9 + 10 ];
59 int logCount;
60
61 if( verboseLevel == 5 || (verboseLevel >= 3 && buffoffset == readto) )
62 {
63 if( verboseLevel == 3 && buffoffset > 11 )
64 logCount = 11;
65 else
66 logCount = buffoffset;
67
68 for( int t = 0; t < logCount; t++ )
69 sprintf( &logBuff[t*9], "[%3d:%02x] ", t, buff.b[t] );
70 if( logCount != buffoffset )
71 sprintf( &logBuff[logCount*9], "... " );
72
73 log( 3, "%s%s", message, logBuff );
74 }
75}
76
77void processRequests( SerialAccess *serial, Image *image0, Image *image1, int timeoutEnabled, int verboseLevel )
78{
79 unsigned char workCommand;
80 int workOffset, workCount;
81
82 unsigned long mylba;
83 unsigned long readto;
84 unsigned long buffoffset;
85 unsigned long lasttick;
86 unsigned short crc;
87 unsigned long GetTime_Timeout_Local;
88 unsigned long len;
89 Image *img;
90 unsigned long cyl, sect, head;
91 unsigned long perfTimer;
92 unsigned char lastScan;
93
94 GetTime_Timeout_Local = GetTime_Timeout();
95
96 buffoffset = 0;
97 readto = 0;
98 workCount = workOffset = workCommand = 0;
99 lastScan = 0;
100
101 lasttick = GetTime();
102
103 while( (len = serial->readCharacters( &buff.b[buffoffset], (readto ? readto-buffoffset : 1) )) )
104 {
105 buffoffset += len;
106
107 //
108 // For debugging, look at the incoming packet
109 //
110 if( verboseLevel >= 3 )
111 logBuff( " Received: ", buffoffset, readto, verboseLevel );
112
113 if( timeoutEnabled && readto && GetTime() > lasttick + GetTime_Timeout_Local )
114 {
115 log( 1, "Timeout waiting on data from client, aborting previous command" );
116
117 workCount = workOffset = workCommand = 0;
118 readto = 0;
119
120 if( len <= 8 && (buff.b[buffoffset-len] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER )
121 {
122 // assume that we are at the front of a new command
123 //
124 memcpy( &buff.b[0], &buff.b[buffoffset-len], len );
125 buffoffset = len;
126 readto = 8;
127 // fall through to normal processing
128 }
129 else if( len == 1 )
130 {
131 // one new character, treat it like any other new character received, discarding the buffer
132 //
133 buff.b[0] = buff.b[buffoffset-1];
134 buffoffset = 1;
135 // fall through to normal processing
136 }
137 else
138 {
139 // discard even the newly received data and start listening anew
140 //
141 buffoffset = 0;
142 continue;
143 }
144 }
145
146 lasttick = GetTime();
147
148 //
149 // No work currently to do, look at each character as they come in...
150 //
151 if( !readto )
152 {
153 if( (buff.b[0] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER )
154 {
155 //
156 // Found our command header byte to start a commnad sequence, read the next 7 and evaluate
157 //
158 readto = 8;
159 continue;
160 }
161 else
162 {
163 //
164 // Spurious characters, discard
165 //
166 if( verboseLevel >= 2 )
167 {
168 if( buff.b[0] >= 0x20 && buff.b[0] <= 0x7e )
169 log( 2, "Spurious: [%d:%c]", buff.b[0], buff.b[0] );
170 else
171 log( 2, "Spurious: [%d]", buff.b[0] );
172 }
173 buffoffset = 0;
174 continue;
175 }
176 }
177
178 //
179 // Partial packet received, keep reading...
180 //
181 if( readto && buffoffset < readto )
182 continue;
183
184 //
185 // Read 512 bytes from serial port, only one command reads that many characters: Write Sector
186 //
187 if( buffoffset == readto && readto == 514 )
188 {
189 buffoffset = readto = 0;
190 if( (crc = checksum( &buff.w[0], 256 )) != buff.w[256] )
191 {
192 log( 0, "Bad Write Sector Checksum" );
193 continue;
194 }
195
196 if( img->readOnly )
197 {
198 log( 1, "Attempt to write to read-only image" );
199 continue;
200 }
201
202 img->seekSector( mylba + workOffset );
203 img->writeSector( &buff.w[0] );
204
205 //
206 // Echo back the CRC
207 //
208 if( !serial->writeCharacters( &buff.w[256], 2 ) )
209 break;
210
211 workOffset++;
212 workCount--;
213
214 if( workCount )
215 readto = 1; // looking for continuation ACK
216 }
217
218 //
219 // 8 byte command received, or a continuation of the previous command
220 //
221 else if( (buffoffset == readto && readto == 8) ||
222 (buffoffset == readto && readto == 1 && workCount) )
223 {
224 buffoffset = readto = 0;
225 if( workCount )
226 {
227 if( verboseLevel > 1 )
228 log( 2, " Continuation: Offset=%u, Checksum=%04x", workOffset-1, buff.w[256] );
229
230 //
231 // Continuation...
232 //
233 if( buff.b[0] != (workCount-0) )
234 {
235 log( 0, "Continue Fault: Received=%d, Expected=%d", buff.b[0], workCount );
236 workCount = 0;
237 continue;
238 }
239 }
240 else
241 {
242 //
243 // New Command...
244 //
245 if( (crc = checksum( &buff.w[0], 3 )) != buff.w[3] )
246 {
247 log( 0, "Bad Command Checksum: %02x %02x %02x %02x %02x %02x %02x %02x, Checksum=%04x",
248 buff.b[0], buff.b[1], buff.b[2], buff.b[3], buff.b[4], buff.b[5], buff.b[6], buff.b[7], crc);
249 continue;
250 }
251
252 img = (buff.inquire.driveAndHead & ATA_DriveAndHead_Drive) ? image1 : image0;
253
254 workCommand = buff.chs.command & SERIAL_COMMAND_RWMASK;
255
256 if( (workCommand != SERIAL_COMMAND_INQUIRE) && (buff.chs.driveAndHead & ATA_COMMAND_LBA) )
257 {
258 mylba = ((((unsigned long) buff.lba.bits24) & ATA_COMMAND_HEADMASK) << 24)
259 | (((unsigned long) buff.lba.bits16) << 16)
260 | (((unsigned long) buff.lba.bits08) << 8)
261 | ((unsigned long) buff.lba.bits00);
262 }
263 else
264 {
265 cyl = buff.chs.cylinder;
266 sect = buff.chs.sector;
267 head = (buff.chs.driveAndHead & ATA_COMMAND_HEADMASK);
268 mylba = img ? (((cyl*img->head + head)*img->sect) + sect-1) : 0;
269 }
270
271 workOffset = 0;
272 workCount = buff.chs.count;
273
274 if( verboseLevel > 0 )
275 {
276 char *comStr = (workCommand & SERIAL_COMMAND_WRITE ? "Write" : "Read");
277
278 if( workCommand == SERIAL_COMMAND_INQUIRE )
279 log( 1, "Inquire %d: Client Port=0x%x, Client Baud=%s", img == image0 ? 0 : 1,
280 ((unsigned short) buff.inquire.port) << 2,
281 baudRateMatchDivisor( buff.inquire.baud )->display );
282 else if( buff.chs.driveAndHead & ATA_COMMAND_LBA )
283 log( 1, "%s %d: LBA=%u, Count=%u", comStr, img == image0 ? 0 : 1,
284 mylba, workCount );
285 else
286 log( 1, "%s %d: Cylinder=%u, Sector=%u, Head=%u, Count=%u, LBA=%u", comStr, img == image0 ? 0 : 1,
287 cyl, sect, head, workCount, mylba );
288 }
289
290 if( !img )
291 {
292 log( 1, " No slave drive provided" );
293 workCount = 0;
294 continue;
295 }
296
297 if( (workCommand & SERIAL_COMMAND_WRITE) && img->readOnly )
298 {
299 log( 1, " Write attempt to Read Only disk" );
300 workCount = 0;
301 continue;
302 }
303
304 if( verboseLevel > 0 && workCount > 100 )
305 perfTimer = GetTime();
306 }
307
308 if( workCount && (workCommand == (SERIAL_COMMAND_WRITE | SERIAL_COMMAND_READWRITE)) )
309 {
310 //
311 // Write command... Setup to receive a sector
312 //
313 readto = 514;
314 }
315 else
316 {
317 //
318 // Inquire command...
319 //
320 if( workCommand == SERIAL_COMMAND_INQUIRE )
321 {
322 unsigned char localScan;
323
324 if( serial->speedEmulation &&
325 buff.inquire.baud != serial->baudRate->divisor )
326 {
327 log( 1, " Ignoring Inquire with wrong baud rate" );
328 workCount = 0;
329 continue;
330 }
331
332 localScan = buff.inquire.scan; // need to do this before the call to
333 // img->respondInquire, as it will clear the buff
334 img->respondInquire( &buff.w[0], serial->baudRate,
335 ((unsigned short) buff.inquire.port) << 2,
336 (img == image1 && lastScan) || buff.inquire.scan );
337 lastScan = localScan;
338 }
339 //
340 // Read command...
341 //
342 else
343 {
344 img->seekSector( mylba + workOffset );
345 img->readSector( &buff.w[0] );
346 lastScan = 0;
347 }
348
349 buff.w[256] = checksum( &buff.w[0], 256 );
350
351 if( !serial->writeCharacters( &buff.w[0], 514 ) )
352 break;
353
354 if( verboseLevel >= 3 )
355 logBuff( " Sending: ", 514, 514, verboseLevel );
356
357 workCount--;
358 workOffset++;
359
360 if( workCount )
361 readto = 1; // looking for continuation ACK
362 }
363 }
364
365 if( workCount == 0 && workOffset > 100 )
366 log( 1, " Performance: %.2lf bytes per second", (512.0 * workOffset) / (GetTime() - perfTimer) * 1000.0 );
367 }
368}
369
370
Note: See TracBrowser for help on using the repository browser.