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

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

More minor improvements to the serial server, in particular improved timeout recovery.

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