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

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

Serial Server: various improvements, turned on LBA28 support by default.

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
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_BAUDMASK 3
51#define SERIAL_INQUIRE_PORTANDBAUD_PORTMASK 0xfc
52#define SERIAL_INQUIRE_PORTANDBAUD_STARTINGPORT 0x240
53
54#define SERIAL_INQUIRE_PORTANDBAUD_PORTTRANSLATE( a ) ( ((a) & SERIAL_INQUIRE_PORTANDBAUD_PORT) << 1 | SERIAL_INQUIRE_PORTANDBAUD_STARTINGPORT )
55
56void logBuff( char *message, unsigned long buffoffset, unsigned long readto, int verboseLevel )
57{
58    char logBuff[ 514*9 + 10 ];
59    int logCount;
60
61    if( verboseLevel == 5 || (verboseLevel >= 3 && buffoffset == readto) )
62    {
63        if( verboseLevel == 3 && buffoffset > 11 )
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
73        log( 3, "%s%s", message, logBuff );
74    }
75}
76
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;
91    unsigned long perfTimer;
92
93    GetTime_Timeout_Local = GetTime_Timeout();
94
95    buffoffset = 0;
96    readto = 0;
97    workCount = workOffset = workCommand = 0;
98
99    lasttick = GetTime();
100
101    while( (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        if( timeoutEnabled && readto && GetTime() > lasttick + GetTime_Timeout_Local )
112        {
113            log( 1, "Timeout waiting on data from client, aborting previous command" );
114
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            }
142        }
143
144        lasttick = GetTime();
145
146        //
147        // No work currently to do, look at each character as they come in...
148        //
149        if( !readto )
150        {
151            if( (buff.b[0] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER )
152            {
153                //
154                // Found our command header byte to start a commnad sequence, read the next 7 and evaluate
155                //
156                readto = 8;
157                continue;
158            }
159            else
160            {
161                //
162                // Spurious characters, discard
163                //
164                if( verboseLevel >= 2 )
165                {
166                    if( buff.b[0] >= 0x20 && buff.b[0] <= 0x7e )
167                        log( 2, "Spurious: [%d:%c]", buff.b[0], buff.b[0] );
168                    else
169                        log( 2, "Spurious: [%d]", buff.b[0] );
170                }
171                buffoffset = 0;
172                continue;
173            }
174        }
175
176        //
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        //
185        if( buffoffset == readto && readto == 514 )
186        {
187            buffoffset = readto = 0;
188            if( (crc = checksum( &buff.w[0], 256 )) != buff.w[256] )
189            {
190                log( 0, "Bad Write Sector Checksum" );
191                continue;
192            }
193
194            if( img->readOnly )
195            {
196                log( 1, "Attempt to write to read-only image" );
197                continue;
198            }
199
200            img->seekSector( mylba + workOffset );
201            img->writeSector( &buff.w[0] );
202
203            //
204            // Echo back the CRC
205            //
206            if( serial->writeCharacters( &buff.w[256], 2 ) != 2 )
207                log( 0, "Serial Port Write Error" );
208
209            workOffset++;
210            workCount--;
211
212            if( workCount )
213                readto = 1;           // looking for continuation ACK
214        }
215
216        //
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            {
225                if( verboseLevel > 1 )
226                    log( 2, "    Continuation: Offset=%u, Checksum=%04x", workOffset-1, buff.w[256] );
227
228                //
229                // Continuation...
230                //
231                if( buff.b[0] != (workCount-0) )
232                {
233                    log( 0, "Continue Fault: Received=%d, Expected=%d", buff.b[0], workCount );
234                    workCount = 0;
235                    continue;
236                }
237            }
238            else
239            {
240                //
241                // New Command...
242                //
243                if( (crc = checksum( &buff.w[0], 3 )) != buff.w[3] )
244                {
245                    log( 0, "Bad Command Checksum: %02x %02x %02x %02x %02x %02x %02x %02x, Checksum=%04x",
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
250                img = (buff.inquire.driveAndHead & ATA_DriveAndHead_Drive) ? image1 : image0;
251
252                workCommand = buff.chs.command & SERIAL_COMMAND_RWMASK;
253
254                if( (workCommand != SERIAL_COMMAND_INQUIRE) && (buff.chs.driveAndHead & 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);
266                    mylba = img ? (((cyl*img->head + head)*img->sect) + sect-1) : 0;
267                }
268
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.driveAndHead & 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
296                if( (workCommand & SERIAL_COMMAND_WRITE) && img->readOnly )
297                {
298                    log( 1, "    Write attempt to Read Only disk" );
299                    workCount = 0;
300                    continue;
301                }
302
303                if( verboseLevel > 0 && workCount > 100 )
304                    perfTimer = GetTime();
305            }
306
307            if( workCount && (workCommand == (SERIAL_COMMAND_WRITE | SERIAL_COMMAND_READWRITE)) )
308            {
309                //
310                // Write command...   Setup to receive a sector
311                //
312                readto = 514;
313            }
314            else 
315            {
316                //
317                // Inquire command...
318                //
319                if( workCommand == SERIAL_COMMAND_INQUIRE )
320                {
321                    if( serial->speedEmulation && 
322                        (buff.inquire.portAndBaud & SERIAL_INQUIRE_PORTANDBAUD_BAUDMASK) != serial->baudRate->divisor )
323                    {
324                        log( 1, "    Ignoring Inquire with wrong baud rate" );
325                        workCount = 0;
326                        continue;
327                    }
328
329                    img->respondInquire( &buff.w[0], serial->baudRate, buff.inquire.portAndBaud );
330                }
331                //
332                // Read command...
333                //
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 )
343                    log( 0, "Serial Port Write Error" );
344
345                if( verboseLevel >= 3 )
346                    logBuff( "    Sending: ", 514, 514, verboseLevel );
347
348                workCount--;
349                workOffset++;
350
351                if( workCount )
352                    readto = 1;           // looking for continuation ACK
353            }
354        }
355
356        if( workCount == 0 && workOffset > 100 )
357            log( 1, "    Performance: %.2lf bytes per second", (512.0 * workOffset) / (GetTime() - perfTimer) * 1000.0 );
358    }
359}
360
361
Note: See TracBrowser for help on using the repository browser.