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

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

Serial Server, more minor improvements, added support for larger than 2 GB disks under Win32

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