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

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

Minor improvements to serial server.

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