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
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;
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
[215]51#define SERIAL_INQUIRE_PORTANDBAUD_BAUDMASK 3
52#define SERIAL_INQUIRE_PORTANDBAUD_PORTMASK 0xfc
53#define SERIAL_INQUIRE_PORTANDBAUD_STARTINGPORT 0x240
[209]54
[215]55#define SERIAL_INQUIRE_PORTANDBAUD_PORTTRANSLATE( a ) ( ((a) & SERIAL_INQUIRE_PORTANDBAUD_PORT) << 1 | SERIAL_INQUIRE_PORTANDBAUD_STARTINGPORT )
56
[219]57#define ATA_COMMAND_LBA 0x40
58#define ATA_COMMAND_HEADMASK 0xf
59
60#define ATA_DriveAndHead_Drive 0x10
61
[210]62void logBuff( char *message, unsigned long buffoffset, unsigned long readto, int verboseLevel )
63{
64    char logBuff[ 514*9 + 10 ];
65    int logCount;
66
[213]67    if( verboseLevel == 5 || (verboseLevel >= 3 && buffoffset == readto) )
[210]68    {
[213]69        if( verboseLevel == 3 && buffoffset > 11 )
[210]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
[211]79        log( 3, "%s%s", message, logBuff );
[210]80    }
81}
82
[219]83void processRequests( SerialAccess *serial, Image *image0, Image *image1, int timeoutEnabled, int verboseLevel )
[209]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;
[210]97    unsigned long perfTimer;
[209]98
99    GetTime_Timeout_Local = GetTime_Timeout();
100
101    buffoffset = 0;
102    readto = 0;
103    workCount = workOffset = workCommand = 0;
[215]104
[209]105    lasttick = GetTime();
106
[215]107    while( (len = serial->readCharacters( &buff.b[buffoffset], (readto ? readto-buffoffset : 1) )) )
[209]108    {
109        buffoffset += len;
110
[210]111        //
112        // For debugging, look at the incoming packet
113        //
[213]114        if( verboseLevel >= 3 )
[210]115            logBuff( "    Received: ", buffoffset, readto, verboseLevel );
[209]116
[215]117        if( timeoutEnabled && readto && GetTime() > lasttick + GetTime_Timeout_Local )
118        {
119            log( 1, "Timeout waiting on data from client, aborting previous command" );
[209]120
[215]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            }
[209]148        }
149
150        lasttick = GetTime();
151
[210]152        //
153        // No work currently to do, look at each character as they come in...
154        //
[215]155        if( !readto )
[209]156        {
[215]157            if( (buff.b[0] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER )
[209]158            {
[210]159                //
160                // Found our command header byte to start a commnad sequence, read the next 7 and evaluate
161                //
[209]162                readto = 8;
[210]163                continue;
[209]164            }
165            else
166            {
[210]167                //
168                // Spurious characters, discard
169                //
[209]170                if( verboseLevel >= 2 )
171                {
172                    if( buff.b[0] >= 0x20 && buff.b[0] <= 0x7e )
[211]173                        log( 2, "Spurious: [%d:%c]", buff.b[0], buff.b[0] );
[209]174                    else
[211]175                        log( 2, "Spurious: [%d]", buff.b[0] );
[209]176                }
177                buffoffset = 0;
178                continue;
179            }
180        }
181
182        //
[210]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        //
[209]191        if( buffoffset == readto && readto == 514 )
192        {
193            buffoffset = readto = 0;
194            if( (crc = checksum( &buff.w[0], 256 )) != buff.w[256] )
195            {
[211]196                log( 0, "Bad Write Sector Checksum" );
[209]197                continue;
198            }
199
200            if( img->readOnly )
201            {
[211]202                log( 1, "Attempt to write to read-only image" );
[209]203                continue;
204            }
205
206            img->seekSector( mylba + workOffset );
207            img->writeSector( &buff.w[0] );
208
[210]209            //
210            // Echo back the CRC
211            //
[219]212            if( !serial->writeCharacters( &buff.w[256], 2 ) )
213                break;
[209]214
215            workOffset++;
216            workCount--;
[215]217
218            if( workCount )
219                readto = 1;           // looking for continuation ACK
[209]220        }
221
[210]222        //
[209]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            {
[215]231                if( verboseLevel > 1 )
232                    log( 2, "    Continuation: Offset=%u, Checksum=%04x", workOffset-1, buff.w[256] );
233
[210]234                //
235                // Continuation...
236                //
[209]237                if( buff.b[0] != (workCount-0) )
238                {
[211]239                    log( 0, "Continue Fault: Received=%d, Expected=%d", buff.b[0], workCount );
[209]240                    workCount = 0;
241                    continue;
242                }
243            }
244            else
245            {
[210]246                //
247                // New Command...
248                //
[209]249                if( (crc = checksum( &buff.w[0], 3 )) != buff.w[3] )
250                {
[215]251                    log( 0, "Bad Command Checksum: %02x %02x %02x %02x %02x %02x %02x %02x, Checksum=%04x",
[209]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
[215]256                img = (buff.inquire.driveAndHead & ATA_DriveAndHead_Drive) ? image1 : image0;
[209]257
258                workCommand = buff.chs.command & SERIAL_COMMAND_RWMASK;
259
[217]260                if( (workCommand != SERIAL_COMMAND_INQUIRE) && (buff.chs.driveAndHead & ATA_COMMAND_LBA) )
[209]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);
[215]272                    mylba = img ? (((cyl*img->head + head)*img->sect) + sect-1) : 0;
[209]273                }
274
[215]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 );
[217]287                    else if( buff.chs.driveAndHead & ATA_COMMAND_LBA )
[215]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
[209]302                if( (workCommand & SERIAL_COMMAND_WRITE) && img->readOnly )
303                {
[215]304                    log( 1, "    Write attempt to Read Only disk" );
305                    workCount = 0;
[209]306                    continue;
307                }
308
[213]309                if( verboseLevel > 0 && workCount > 100 )
[210]310                    perfTimer = GetTime();
[209]311            }
312
313            if( workCount && (workCommand == (SERIAL_COMMAND_WRITE | SERIAL_COMMAND_READWRITE)) )
314            {
[210]315                //
316                // Write command...   Setup to receive a sector
317                //
[209]318                readto = 514;
319            }
320            else 
321            {
[210]322                //
323                // Inquire command...
324                //
[209]325                if( workCommand == SERIAL_COMMAND_INQUIRE )
326                {
327                    if( serial->speedEmulation && 
[215]328                        (buff.inquire.portAndBaud & SERIAL_INQUIRE_PORTANDBAUD_BAUDMASK) != serial->baudRate->divisor )
[209]329                    {
[215]330                        log( 1, "    Ignoring Inquire with wrong baud rate" );
[209]331                        workCount = 0;
332                        continue;
333                    }
334
335                    img->respondInquire( &buff.w[0], serial->baudRate, buff.inquire.portAndBaud );
336                }
[210]337                //
338                // Read command...
339                //
[209]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
[219]348                if( !serial->writeCharacters( &buff.w[0], 514 ) )
349                    break;
[209]350
[215]351                if( verboseLevel >= 3 )
352                    logBuff( "    Sending: ", 514, 514, verboseLevel );
353
[209]354                workCount--;
355                workOffset++;
[215]356
357                if( workCount )
358                    readto = 1;           // looking for continuation ACK
[209]359            }
[210]360        }
[209]361
[215]362        if( workCount == 0 && workOffset > 100 )
363            log( 1, "    Performance: %.2lf bytes per second", (512.0 * workOffset) / (GetTime() - perfTimer) * 1000.0 );
[209]364    }
365}
[210]366
367
Note: See TracBrowser for help on using the repository browser.