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

Last change on this file since 219 was 219, checked in by gregli@…, 12 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.