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

Last change on this file since 248 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
RevLine 
[209]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>
[219]11#include <stdio.h>
[209]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;
[233]33 unsigned char scan;
34 unsigned char port;
35 unsigned char baud;
[209]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
[219]51#define ATA_COMMAND_LBA 0x40
52#define ATA_COMMAND_HEADMASK 0xf
53
54#define ATA_DriveAndHead_Drive 0x10
55
[210]56void logBuff( char *message, unsigned long buffoffset, unsigned long readto, int verboseLevel )
57{
58 char logBuff[ 514*9 + 10 ];
59 int logCount;
60
[213]61 if( verboseLevel == 5 || (verboseLevel >= 3 && buffoffset == readto) )
[210]62 {
[213]63 if( verboseLevel == 3 && buffoffset > 11 )
[210]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
[211]73 log( 3, "%s%s", message, logBuff );
[210]74 }
75}
76
[219]77void processRequests( SerialAccess *serial, Image *image0, Image *image1, int timeoutEnabled, int verboseLevel )
[209]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;
[210]91 unsigned long perfTimer;
[233]92 unsigned char lastScan;
[209]93
94 GetTime_Timeout_Local = GetTime_Timeout();
95
96 buffoffset = 0;
97 readto = 0;
98 workCount = workOffset = workCommand = 0;
[233]99 lastScan = 0;
[215]100
[209]101 lasttick = GetTime();
102
[215]103 while( (len = serial->readCharacters( &buff.b[buffoffset], (readto ? readto-buffoffset : 1) )) )
[209]104 {
105 buffoffset += len;
106
[210]107 //
108 // For debugging, look at the incoming packet
109 //
[213]110 if( verboseLevel >= 3 )
[210]111 logBuff( " Received: ", buffoffset, readto, verboseLevel );
[209]112
[215]113 if( timeoutEnabled && readto && GetTime() > lasttick + GetTime_Timeout_Local )
114 {
115 log( 1, "Timeout waiting on data from client, aborting previous command" );
[209]116
[215]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 }
[209]144 }
145
146 lasttick = GetTime();
147
[210]148 //
149 // No work currently to do, look at each character as they come in...
150 //
[215]151 if( !readto )
[209]152 {
[215]153 if( (buff.b[0] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER )
[209]154 {
[210]155 //
156 // Found our command header byte to start a commnad sequence, read the next 7 and evaluate
157 //
[209]158 readto = 8;
[210]159 continue;
[209]160 }
161 else
162 {
[210]163 //
164 // Spurious characters, discard
165 //
[209]166 if( verboseLevel >= 2 )
167 {
168 if( buff.b[0] >= 0x20 && buff.b[0] <= 0x7e )
[211]169 log( 2, "Spurious: [%d:%c]", buff.b[0], buff.b[0] );
[209]170 else
[211]171 log( 2, "Spurious: [%d]", buff.b[0] );
[209]172 }
173 buffoffset = 0;
174 continue;
175 }
176 }
177
178 //
[210]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 //
[209]187 if( buffoffset == readto && readto == 514 )
188 {
189 buffoffset = readto = 0;
190 if( (crc = checksum( &buff.w[0], 256 )) != buff.w[256] )
191 {
[211]192 log( 0, "Bad Write Sector Checksum" );
[209]193 continue;
194 }
195
196 if( img->readOnly )
197 {
[211]198 log( 1, "Attempt to write to read-only image" );
[209]199 continue;
200 }
201
202 img->seekSector( mylba + workOffset );
203 img->writeSector( &buff.w[0] );
204
[210]205 //
206 // Echo back the CRC
207 //
[219]208 if( !serial->writeCharacters( &buff.w[256], 2 ) )
209 break;
[209]210
211 workOffset++;
212 workCount--;
[215]213
214 if( workCount )
215 readto = 1; // looking for continuation ACK
[209]216 }
217
[210]218 //
[209]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 {
[215]227 if( verboseLevel > 1 )
228 log( 2, " Continuation: Offset=%u, Checksum=%04x", workOffset-1, buff.w[256] );
229
[210]230 //
231 // Continuation...
232 //
[209]233 if( buff.b[0] != (workCount-0) )
234 {
[211]235 log( 0, "Continue Fault: Received=%d, Expected=%d", buff.b[0], workCount );
[209]236 workCount = 0;
237 continue;
238 }
239 }
240 else
241 {
[210]242 //
243 // New Command...
244 //
[209]245 if( (crc = checksum( &buff.w[0], 3 )) != buff.w[3] )
246 {
[215]247 log( 0, "Bad Command Checksum: %02x %02x %02x %02x %02x %02x %02x %02x, Checksum=%04x",
[209]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
[215]252 img = (buff.inquire.driveAndHead & ATA_DriveAndHead_Drive) ? image1 : image0;
[209]253
254 workCommand = buff.chs.command & SERIAL_COMMAND_RWMASK;
255
[217]256 if( (workCommand != SERIAL_COMMAND_INQUIRE) && (buff.chs.driveAndHead & ATA_COMMAND_LBA) )
[209]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);
[215]268 mylba = img ? (((cyl*img->head + head)*img->sect) + sect-1) : 0;
[209]269 }
270
[215]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,
[233]280 ((unsigned short) buff.inquire.port) << 2,
281 baudRateMatchDivisor( buff.inquire.baud )->display );
[217]282 else if( buff.chs.driveAndHead & ATA_COMMAND_LBA )
[215]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
[209]297 if( (workCommand & SERIAL_COMMAND_WRITE) && img->readOnly )
298 {
[215]299 log( 1, " Write attempt to Read Only disk" );
300 workCount = 0;
[209]301 continue;
302 }
303
[213]304 if( verboseLevel > 0 && workCount > 100 )
[210]305 perfTimer = GetTime();
[209]306 }
307
308 if( workCount && (workCommand == (SERIAL_COMMAND_WRITE | SERIAL_COMMAND_READWRITE)) )
309 {
[210]310 //
311 // Write command... Setup to receive a sector
312 //
[209]313 readto = 514;
314 }
315 else
316 {
[210]317 //
318 // Inquire command...
319 //
[209]320 if( workCommand == SERIAL_COMMAND_INQUIRE )
321 {
[233]322 unsigned char localScan;
323
[209]324 if( serial->speedEmulation &&
[233]325 buff.inquire.baud != serial->baudRate->divisor )
[209]326 {
[215]327 log( 1, " Ignoring Inquire with wrong baud rate" );
[209]328 workCount = 0;
329 continue;
330 }
331
[233]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;
[209]338 }
[210]339 //
340 // Read command...
341 //
[209]342 else
343 {
344 img->seekSector( mylba + workOffset );
345 img->readSector( &buff.w[0] );
[233]346 lastScan = 0;
[209]347 }
348
349 buff.w[256] = checksum( &buff.w[0], 256 );
350
[219]351 if( !serial->writeCharacters( &buff.w[0], 514 ) )
352 break;
[209]353
[215]354 if( verboseLevel >= 3 )
355 logBuff( " Sending: ", 514, 514, verboseLevel );
356
[209]357 workCount--;
358 workOffset++;
[215]359
360 if( workCount )
361 readto = 1; // looking for continuation ACK
[209]362 }
[210]363 }
[209]364
[215]365 if( workCount == 0 && workOffset > 100 )
366 log( 1, " Performance: %.2lf bytes per second", (512.0 * workOffset) / (GetTime() - perfTimer) * 1000.0 );
[209]367 }
368}
[210]369
370
Note: See TracBrowser for help on using the repository browser.