OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [host/] [tools/] [ecostest/] [common/] [eCosTestSerialFilter.cpp] - Blame information for rev 790

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
// ####ECOSHOSTGPLCOPYRIGHTBEGIN####                                        
2
// -------------------------------------------                              
3
// This file is part of the eCos host tools.                                
4
// Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.            
5
//
6
// This program is free software; you can redistribute it and/or modify     
7
// it under the terms of the GNU General Public License as published by     
8
// the Free Software Foundation; either version 2 or (at your option) any   
9
// later version.                                                           
10
//
11
// This program is distributed in the hope that it will be useful, but      
12
// WITHOUT ANY WARRANTY; without even the implied warranty of               
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        
14
// General Public License for more details.                                 
15
//
16
// You should have received a copy of the GNU General Public License        
17
// along with this program; if not, write to the                            
18
// Free Software Foundation, Inc., 51 Franklin Street,                      
19
// Fifth Floor, Boston, MA  02110-1301, USA.                                
20
// -------------------------------------------                              
21
// ####ECOSHOSTGPLCOPYRIGHTEND####                                          
22
//=================================================================
23
//
24
//        eCosTestSerialFilter.cpp
25
//
26
//        Serial test filter class
27
//
28
//=================================================================
29
//=================================================================
30
//#####DESCRIPTIONBEGIN####
31
//
32
// Author(s):     jskov
33
// Contributors:  jskov
34
// Date:          1999-03-01
35
// Description:   This filter sits between GDB and the test running on
36
//                the target, allowing testing of the serial driver 
37
//                without confusing GDB.
38
// To Do:
39
//  o Add timeout setup and handling for recovery, can rely on testing
40
//    agent to control global timeout.
41
//  o Saving chunks that caused transfer failure?
42
//     - In SEND with echo, do CRC on 32-byte sub-packets
43
//  o Additional To Do items under each sub-protocol function.
44
//  o Option to get all serial IO written (in hex, > and < prepends 
45
//    input/output lines) to a file.
46
//  o Clean up the mess in this file....
47
//####DESCRIPTIONEND####
48
 
49
#include "eCosStd.h"
50
 
51
#include "eCosTestSerialFilter.h"
52
#include "eCosThreadUtils.h"
53
 
54
char msg_ok[] = "OK";
55
char msg_er[] = "ER";
56
 
57
 
58
 
59
CeCosTestSerialFilter::CeCosTestSerialFilter():
60
  m_bOptConsoleOutput(false),
61
  m_bOptSerDebug(false),
62
  m_bOptFilterTrace(false),
63
  m_xUnreadBuffer(NULL),
64
  m_nUnreadBufferIndex(0),
65
  m_nUnreadBufferSize(0),
66
  m_xStoredTraceBuffer(NULL),
67
  m_nStoredTraceBufferSize(0),
68
  m_bNullFilter(false),
69
  m_nCmdIndex(0),
70
  m_bCmdFlag(false),
71
  m_bFirstCommandSeen(false),
72
  m_cGDBSocket(NULL)
73
{
74
}
75
 
76
CeCosTestSerialFilter::~CeCosTestSerialFilter()
77
{
78
}
79
 
80
//------------------------
81
// Output helpers.
82
 
83
// Encode string in an O-packet and send it to GDB.
84
void
85
CeCosTestSerialFilter::GDBWrite(const char* pszStr)
86
{
87
    if (m_cGDBSocket) {
88
        static const char hexchars[] = "0123456789abcdef";
89
        char* packet = new char[strlen(pszStr)*2+6];
90
        char* p = packet;
91
 
92
        *p++ = '$';
93
        *p++ = 'O';
94
        unsigned char crc = 'O';
95
        char c;
96
        for (;;) {
97
            c = *pszStr++;
98
            if (0 == c)
99
                break;
100
 
101
            char h = hexchars[(c >> 4) & 0x0f];
102
            char l = hexchars[c & 0x0f];
103
            *p++ = h;
104
            *p++ = l;
105
            crc = (unsigned char) (crc + h + l);
106
        };
107
 
108
        *p++ = '#';
109
        *p++ = hexchars[(crc >> 4) & 0x0f];
110
        *p++ = hexchars[crc & 0x0f];
111
 
112
        // Only try to send once. If it fails, it's probably because
113
        // GDB has disconnected.
114
        m_cGDBSocket->send(packet, p - packet);
115
        m_cGDBSocket->recv(&c, 1);
116
 
117
        delete [] packet;
118
    }
119
}
120
 
121
void
122
CeCosTestSerialFilter::ConsoleWrite(const char* pszStr)
123
{
124
    fputs(pszStr, stderr);
125
    fflush(stderr);
126
}
127
 
128
void
129
CeCosTestSerialFilter::Trace(const char* pszFormat, ...)
130
{
131
 
132
  va_list marker;
133
  va_start (marker, pszFormat);
134
 
135
  for(int nLength=100;nLength;) {
136
    char *buf=new char[1+nLength];
137
    int n=vsnprintf(buf+4, nLength-4, pszFormat, marker );
138
    if(-1==n){
139
      nLength*=2;  // NT behavior
140
    } else if (n<nLength){
141
      memcpy(buf,"[f] ",4);
142
      if (m_bOptConsoleOutput) {
143
        ConsoleWrite(buf);
144
      } else {
145
        GDBWrite(buf);
146
      }
147
      nLength=0;   // trigger exit from loop
148
    } else {
149
      nLength=n+1; // UNIX behavior generally, or NT behavior when buffer size exactly matches required length
150
    }
151
    delete [] buf;
152
  }
153
 
154
  va_end (marker);
155
 
156
}
157
 
158
void
159
CeCosTestSerialFilter::Log(const char* pszFormat, ...)
160
{
161
  va_list marker;
162
  va_start (marker, pszFormat);
163
 
164
  for(int nLength=100;nLength;) {
165
    char *buf=new char[1+nLength];
166
    int n=vsnprintf(buf, nLength, pszFormat, marker );
167
    if(-1==n){
168
      nLength*=2;  // NT behavior
169
    } else if (n<nLength){
170
      if (m_bOptConsoleOutput) {
171
        ConsoleWrite(buf);
172
      } else {
173
        GDBWrite(buf);
174
      }
175
      nLength=0;   // trigger exit from loop
176
    } else {
177
      nLength=n+1; // UNIX behavior generally, or NT behavior when buffer size exactly matches required length
178
    }
179
    delete [] buf;
180
  }
181
 
182
  va_end (marker);
183
}
184
 
185
 
186
void
187
CeCosTestSerialFilter::PrintHex(const unsigned char* d1, int len, data_origin_t origin/*=SF_TARGET*/)
188
{
189
    int offset = 0;
190
    int i;
191
    char buf[128];
192
    int width = 8;
193
 
194
    while (len) {
195
        int count = MIN(width, len);
196
        char* p = buf;
197
        switch (origin) {
198
        case SF_TARGET:
199
            p += sprintf(p, "T");
200
            break;
201
        case SF_FILTER:
202
            p += sprintf(p, "F");
203
            break;
204
        }
205
        p += sprintf(p, ":%04x ", offset);
206
        // Print hex values.
207
        for (i = 0; i < count; i++)
208
            p += sprintf(p, "%02x ", d1[i]);
209
        for (     ; i < width   ; i++)
210
            p += sprintf(p, ".. ");
211
 
212
        // Print ASCII string
213
        p += sprintf(p, "'");
214
        for (i = 0; i < count; i++) {
215
            int c = d1[i];
216
            if (' ' > c || 'z' < c)
217
                c = '.';
218
            p += sprintf(p, "%c", c);
219
        }
220
        sprintf(p, "'\n");
221
 
222
        Trace("%s", buf);
223
 
224
        len -= count;
225
        offset += count;
226
        d1 += count;
227
    }
228
}
229
 
230
void
231
CeCosTestSerialFilter::TargetWrite(CeCosSerial &pSer,
232
                                    const unsigned char* buffer, int len)
233
{
234
    unsigned int __written;
235
 
236
    if (m_bOptFilterTrace)
237
        PrintHex(buffer, len, SF_FILTER);
238
 
239
    do {
240
        if (!(pSer.Write((void*) buffer, len, __written))) {
241
            fprintf(stderr, "Writing %d bytes to serial failed\n", len);
242
            fprintf(stderr, "%s", (LPCTSTR)pSer.ErrString());
243
            throw "serial write failed";
244
        }
245
        buffer += __written;
246
        len -= __written;
247
    } while (len);
248
 
249
}
250
 
251
 
252
bool
253
CeCosTestSerialFilter::TargetRead(CeCosSerial &pSer,
254
                                  unsigned char* buffer, int len)
255
{
256
    unsigned int __read;
257
    int __total_read = 0;
258
    unsigned char* __buffer_base = buffer;
259
    int __timeouts = 0;
260
    int __timeout_failure = 0;
261
    int __orig_len = len;
262
 
263
    do {
264
        // First check for unread data.
265
        if (m_nUnreadBufferSize) {
266
            int i = 0;
267
            __read = 0;
268
            while (i < len && m_nUnreadBufferIndex < m_nUnreadBufferSize) {
269
                buffer[i++] = m_xUnreadBuffer[m_nUnreadBufferIndex++];
270
                __read++;
271
            }
272
 
273
            if (m_nUnreadBufferIndex == m_nUnreadBufferSize) {
274
                free(m_xUnreadBuffer);
275
                m_nUnreadBufferSize = 0;
276
                m_nUnreadBufferIndex = 0;
277
            }
278
        } else {
279
            // Then read directly from serial.
280
            if (!(pSer.Read((void*) buffer, len, __read))) {
281
                fprintf(stderr,"Reading %d bytes from serial failed (read %d).\n",
282
                        len, __read);
283
                char *pszErr=pSer.ErrString().GetCString();
284
                fprintf(stderr, "%s", pszErr);
285
                delete [] pszErr;
286
                throw "serial read failed";
287
            }
288
        }
289
 
290
        __total_read += __read;
291
        unsigned int i;
292
        for (i = 0; i < __read; i++) {
293
            if ('$' == buffer[i]) {
294
 
295
                Log("FAIL:<target crashed>\n");
296
 
297
                Trace("**** Detected $ -- resuming as null filter ****\n");
298
 
299
                Trace("Data received %d bytes (of %d) from target:\n",
300
                      __total_read, __orig_len);
301
                PrintHex(__buffer_base, __total_read);
302
                Trace("<end>\n");
303
 
304
                filter_abort_t* msg = new filter_abort_t();
305
                msg->data_ptr = &buffer[i];
306
                msg->data_len = __read - i;
307
 
308
                throw msg;
309
            }
310
        }
311
 
312
        if (0 == __read) {
313
            CeCosThreadUtils::Sleep(20);
314
            __timeouts++;
315
            if (25 == __timeouts) {
316
                __timeouts = 0;
317
                if (5 == __timeout_failure++) {
318
                    Log("FAIL:<target timed out>\n");
319
 
320
                    Trace("**** Timed out while reading -- resuming as null filter\n");
321
 
322
                    Trace("Data received %d bytes (of %d) from target:\n",
323
                          __total_read, __orig_len);
324
                    PrintHex(__buffer_base, __total_read);
325
                    Trace("<end>\n");
326
 
327
                    static const char kill_msg[] = "$X00#b8";
328
 
329
                    filter_abort_t* msg = new filter_abort_t();
330
                    msg->data_len = strlen(kill_msg);
331
                    msg->data_ptr = (const unsigned char *)kill_msg;
332
 
333
                    throw msg;
334
                }
335
            }
336
        } else {
337
            __timeouts = 0;
338
            __timeout_failure = 0;
339
        }
340
 
341
        buffer += __read;
342
        len -= __read;
343
 
344
    } while (len);
345
 
346
    return true;
347
}
348
 
349
// Send C ASCII string to target.
350
void
351
CeCosTestSerialFilter::TargetASCIIWrite(CeCosSerial &pSer, const char* s)
352
{
353
    TargetWrite(pSer, (const unsigned char*) s, strlen(s));
354
}
355
 
356
//------------------------
357
// Configuration Command.
358
// Set serial configuration.
359
bool
360
CeCosTestSerialFilter::SetConfig(CeCosSerial &pSer,
361
                                 const ser_cfg_t* new_cfg,
362
                                 ser_cfg_t* old_cfg)
363
{
364
    // Note that for flow control, we assume that *both* receive and transmit
365
    // flow control are set or not set
366
    if (old_cfg) {
367
        old_cfg->baud_rate = pSer.GetBaud();
368
        old_cfg->parity = (0 != pSer.GetParity()) ? true : false;
369
        old_cfg->data_bits = pSer.GetDataBits();
370
        old_cfg->stop_bits = pSer.GetStopBits();
371
        old_cfg->flags = pSer.GetXONXOFFFlowControl() ? FLOW_XONXOFF_RX : 0;
372
        old_cfg->flags |= pSer.GetRTSCTSFlowControl() ? FLOW_RTSCTS_RX : 0;
373
        old_cfg->flags |= pSer.GetDSRDTRFlowControl() ? FLOW_DSRDTR_RX : 0;
374
    }
375
 
376
    pSer.SetBaud(new_cfg->baud_rate, false);
377
    pSer.SetParity(new_cfg->parity, false);
378
    pSer.SetDataBits(new_cfg->data_bits, false);
379
    pSer.SetXONXOFFFlowControl((new_cfg->flags&FLOW_XONXOFF_RX) != 0, false);
380
    pSer.SetRTSCTSFlowControl((new_cfg->flags&FLOW_RTSCTS_RX) != 0, false);
381
    pSer.SetDSRDTRFlowControl((new_cfg->flags&FLOW_DSRDTR_RX) != 0, false);
382
    return pSer.SetStopBits(new_cfg->stop_bits, true); // apply settings
383
}
384
 
385
// Return false if the serial configuration is not valid for the host.
386
bool
387
CeCosTestSerialFilter::VerifyConfig(CeCosSerial &pSer, ser_cfg_t* new_cfg)
388
{
389
    ser_cfg_t old_cfg;
390
    bool rc;
391
 
392
    // Try changing to the new config, recording the result. Then restore
393
    // the original config.
394
    rc = SetConfig(pSer, new_cfg, &old_cfg);
395
    SetConfig(pSer, &old_cfg, NULL);
396
 
397
    return rc;
398
}
399
 
400
//-----------------------------------------------------------------------------
401
// Configuration changing function.
402
//
403
// First change to the new config and back again to determine if the driver
404
// can handle the config.
405
// If not, return error.
406
//
407
// Then query the host for its capability to use the config:
408
// Format out:
409
//  "@CONFIG:<baud rate code>:<#data bits>:<#stop bits>:<parity on/off>!"
410
// Format in:
411
//  OK/ER
412
//
413
// On ER, return error.
414
//
415
// On OK, change to the new configuration. Resynchronize with the host:
416
//  Target waits for host to send S(ync) 
417
//     [host will delay at least .1 secs after changing baud rate so the 
418
//      line has time to settle.]
419
//
420
//  When receiving S(ync), target replies OK to the host which then
421
//  acknowledges with D(one).
422
//
423
//  Host can also send R(esync) which means it didn't receieve the OK. If
424
//  so the target resends its S(ync) message.
425
//
426
// If the synchronization has not succeeded within 1 second
427
// (configurable in the protocol), both host and target will revert to
428
// the previous configuration and attempt to synchronize again. If
429
// this fails, this call will hang and the host will consider the test
430
// a failure.
431
//
432
// To Do:
433
//  Host&protocol currently only supports:
434
//   - no/even parity
435
void
436
CeCosTestSerialFilter::CMD_ChangeConfig(CeCosSerial &pSer, char* cfg_str)
437
{
438
    ser_cfg_t new_cfg, old_cfg;
439
 
440
    ParseConfig(cfg_str, &new_cfg);
441
 
442
    // Return without changing the config if it's not valid.
443
    if (!VerifyConfig(pSer, &new_cfg)) {
444
        TargetASCIIWrite(pSer, "ER");
445
        return;
446
    }
447
 
448
    // Tell target we're ready to go, wait 1/10 sec, and then change
449
    // the config.
450
    TargetASCIIWrite(pSer, "OK");
451
    CeCosThreadUtils::Sleep(100);
452
    SetConfig(pSer, &new_cfg, &old_cfg);
453
 
454
    int loops;
455
    for (loops = 0; loops < 3; loops++) {
456
        unsigned int len, read;
457
        unsigned char buffer[2];
458
        int delay_mticks = 0; // millisecond-ticks. 10 of these per target tick
459
 
460
        // Start by sending a Sync.
461
        TargetASCIIWrite(pSer, "S");
462
        for(;;) {
463
            // Did target reply?
464
            len = 2;
465
            read = 0;
466
            buffer[0] = 0;
467
            buffer[1] = 0;
468
            if (!pSer.Read((void*) buffer, len, read)) {
469
                throw "CMD_ChangeConfig: serial read failure";
470
            }
471
 
472
            if (read) {
473
                // If only one char read, try to get the next one.
474
                if (1 == read) {
475
                    unsigned int read2 = 0;
476
                    len = 1;
477
                    if (!pSer.Read((void*) &buffer[1], len, read2)) {
478
                        throw "CMD_ChangeConfig: serial read failure";
479
                    }
480
                    read += read2;
481
                }
482
 
483
                if (m_bOptSerDebug)
484
                    PrintHex(buffer, read);
485
 
486
                if ('O' == buffer[0] && 'K' == buffer[1]) {
487
                    // success!
488
                    TargetASCIIWrite(pSer, "D");
489
                    Trace("Config change succeeded.\n");
490
                    return;
491
                } else {
492
                    // Garbage, ask target to resend its OK message.
493
                    TargetASCIIWrite(pSer, "R");
494
                }
495
            } else {
496
                // Resend Sync message.
497
                TargetASCIIWrite(pSer, "S");
498
            }
499
 
500
            CeCosThreadUtils::Sleep(1);
501
            delay_mticks++;
502
            // Timeout.
503
            if (100 == delay_mticks/10)
504
                break;
505
        }
506
 
507
        SetConfig(pSer, &old_cfg, NULL);
508
    }
509
 
510
    // Abort the test.
511
    Log("FAIL:<target timed out>\n");
512
    Trace("**** Timed out while changing config\n");
513
 
514
    static const char kill_msg[] = "$X00#b8";
515
 
516
    filter_abort_t* msg = new filter_abort_t();
517
    msg->data_len = strlen(kill_msg);
518
    msg->data_ptr = (const unsigned char *)kill_msg;
519
 
520
    throw msg;
521
}
522
 
523
// Set default configuration.
524
void
525
CeCosTestSerialFilter::CMD_DefaultConfig(CeCosSerial &pSer)
526
{
527
    static const ser_cfg_t default_ser_cfg = { 9600,
528
                                               8,
529
                                               CeCosSerial::ONE_STOP_BIT,
530
                                               false };
531
 
532
    TargetASCIIWrite(pSer, "OK");
533
    SetConfig(pSer, &default_ser_cfg, NULL);
534
}
535
 
536
// Parse config string from target and set new_cfg accordingly.
537
// String from target is:
538
//  <baud rate>:<data bits>:<stop bits>:<parity>:....
539
void
540
CeCosTestSerialFilter::ParseConfig(char* args, ser_cfg_t* new_cfg)
541
{
542
    int ecos_parity, ecos_stop_bits, ecos_baud_rate, ecos_flags;
543
 
544
    CeCosSerial::StopBitsType t2h_stop_bits[3] = {
545
        CeCosSerial::ONE_STOP_BIT,
546
        CeCosSerial::ONE_POINT_FIVE_STOP_BITS,
547
        CeCosSerial::TWO_STOP_BITS};
548
    INIT_VALUE(args);
549
 
550
    SET_VALUE(int, ecos_baud_rate);
551
    SET_VALUE(int, new_cfg->data_bits);
552
    SET_VALUE(int, ecos_stop_bits);
553
    SET_VALUE(int, ecos_parity);
554
    SET_VALUE(int, ecos_flags);
555
 
556
    new_cfg->parity = (ecos_parity != 0) ? true : false;
557
    new_cfg->stop_bits = t2h_stop_bits[ecos_stop_bits - 1];
558
 
559
    // flags is an optional field
560
    if ( -1 == ecos_flags )
561
        new_cfg->flags = FLOW_NONE;
562
    else
563
        new_cfg->flags = ecos_flags;
564
 
565
    // eCos->human translation of serial baud rate. This table must
566
    // match the one in io/serial/current/include/serialio.h
567
    static const int tt_baud_rate[] = {
568
        -1,                                 // 0 invalid
569
        50,                                 // 1 50
570
        75,                                 // 2 75
571
        110,                                // 3
572
        135,                                // 4 134_5
573
        150,                                // 5
574
        200,                                // 6 200
575
        300,                                // 7
576
        600,                                // 8
577
        1200,                               // 9
578
        1800,                               // 10 1800
579
        2400,                               // 11
580
        3600,                               // 12 3600
581
        4800,                               // 13
582
        7200,                               // 14 7200
583
        9600,                               // 15
584
        14400,                              // 16 14400
585
        19200,                              // 17
586
        38400,                              // 18
587
        57600,                              // 19
588
        115200,                             // 20
589
        234000                              // 21 234000
590
    };
591
 
592
    if (ecos_baud_rate > 0 && ecos_baud_rate < (int) sizeof(tt_baud_rate))
593
        ecos_baud_rate = tt_baud_rate[ecos_baud_rate];
594
    else
595
        ecos_baud_rate = -2;
596
 
597
    new_cfg->baud_rate = ecos_baud_rate;
598
 
599
    Trace("Parsed Config baud=%d, bParity=%d, stopbits=%d, databits=%d\n",
600
          new_cfg->baud_rate, (int) new_cfg->parity, new_cfg->stop_bits,
601
          new_cfg->data_bits);
602
    Trace("Parsed Config xonxoff_rx=%d,tx=%d, rtscts_rx=%d,tx=%d, "
603
          "dsrdtr_rx=%d,tx=%d\n",
604
          (new_cfg->flags & FLOW_XONXOFF_RX) != 0,
605
          (new_cfg->flags & FLOW_XONXOFF_TX) != 0,
606
          (new_cfg->flags & FLOW_RTSCTS_RX) != 0,
607
          (new_cfg->flags & FLOW_RTSCTS_TX) != 0,
608
          (new_cfg->flags & FLOW_DSRDTR_RX) != 0,
609
          (new_cfg->flags & FLOW_DSRDTR_TX) != 0);
610
}
611
 
612
// Always make sure CRC fits in 31 bits. Bit of a hack, but we want
613
// to send CRC as ASCII without too much hassle.
614
int
615
CeCosTestSerialFilter::DoCRC(unsigned char* data, int size)
616
{
617
    int i;
618
    unsigned long crc;
619
 
620
    for (i = 0, crc = 0; i < size; i++) {
621
        crc = (crc << 1) ^ data[i];     // FIXME: standard definition?
622
    }
623
 
624
    i = (int) crc;
625
    if (i < 0)
626
        i = -i;
627
 
628
    return i;
629
}
630
 
631
void
632
CeCosTestSerialFilter::SendChecksum(CeCosSerial &pSer, int crc)
633
{
634
    char buffer[128];
635
    int len;
636
 
637
    len = sprintf(buffer, "%d!", crc);
638
 
639
    TargetWrite(pSer, (const unsigned char*)buffer, len);
640
}
641
 
642
void
643
CeCosTestSerialFilter::SendStatus(CeCosSerial &pSer, int state)
644
{
645
    if (state)
646
        TargetWrite(pSer, (unsigned char*) &msg_ok, 2);
647
    else
648
        TargetWrite(pSer, (unsigned char*) &msg_er, 2);
649
}
650
 
651
 
652
// Receive test DONE message from target.
653
void
654
CeCosTestSerialFilter::ReceiveDone(CeCosSerial &pSer,
655
                                   unsigned char* data_in, int size)
656
{
657
    static const char msg_done[] = "DONE";
658
    unsigned char data_reply[4];
659
    int first = 1;
660
 
661
    TargetRead(pSer, data_reply, 4);
662
    while (0 != strncmp((char*) data_reply, msg_done, 4)) {
663
        if (first) {
664
            if (data_in && size) {
665
                Trace("Data received from target:\n");
666
                PrintHex(data_in, size);
667
                Trace("<end>\n");
668
            }
669
            Trace("Receiving junk instead of DONE:\n");
670
            first = 0;
671
        }
672
        PrintHex(data_reply, 4);
673
 
674
        data_reply[0] = data_reply[1];
675
        data_reply[1] = data_reply[2];
676
        data_reply[2] = data_reply[3];
677
 
678
        // The TargetRead call will handle recovery in case of timeout...
679
        TargetRead(pSer, &data_reply[3], 1);
680
    }
681
}
682
 
683
//-----------------------------------------------------------------------------
684
// Test binary data transmission.
685
// Format in:
686
//  <byte size>:<mode>
687
// Format out:
688
//  <4 bytes binary checksum><#size bytes data>
689
// If echo mode, also:
690
//    Format in:
691
//     <#size bytes data>
692
//    Format out:
693
//     OK/ER - according to CRC match on incomin data
694
// Format in:
695
//  DONE
696
//
697
// To Do:
698
//  o Add mode/flag specifying 5-8 bit transfer.
699
//     Test that 0xff gets masked off accordingly when transfered.
700
//     (This should be an INFO result if failing)
701
//  o Clean up the DUPLEX_ECHO implementation. Currently it's an ugly hack
702
//    that doesn't match the arguments / behavior of the two other modes.
703
void
704
CeCosTestSerialFilter::CMD_TestBinary(CeCosSerial &pSer, char* args)
705
{
706
    int size;
707
    cyg_mode_t mode;
708
    unsigned char *data_out, *data_in;
709
    int i;
710
    int crc;
711
 
712
    int loop_count = 0;
713
 
714
    INIT_VALUE(args);
715
 
716
    SET_VALUE(int, size);
717
    SET_VALUE(cyg_mode_t, mode);
718
 
719
    // Change behavior for DUPLEX mode.
720
    if (MODE_DUPLEX_ECHO == mode) {
721
        loop_count = size;
722
        size = 1024;                    // must be at least 4*block_size
723
    }
724
 
725
    // Generate data.
726
    data_out = (unsigned char*) malloc(size);
727
    if (!data_out) {
728
        fprintf(stderr, "Could not allocate %d byte buffer for data!\n", size);
729
        throw "data_out malloc failed";
730
    }
731
    data_in = (unsigned char*) malloc(size);
732
    if (!data_in) {
733
        fprintf(stderr, "Could not allocate %d byte buffer for data!\n", size);
734
        throw "data_in malloc failed";
735
    }
736
    int count = 0;
737
    for (i = 0; i < size; i++) {
738
        // Output 255 chars, not 256 so that we aren't a multiple/factor of the
739
        // likely buffer sizes in the system, this can mask problems as I've
740
        // found to my cost!
741
        unsigned char c = (unsigned char) (count++ % 255);
742
        // don't allow $s and @s in the data, nor 0x03 (GDB C-c), nor flow
743
        // control chars
744
        if ('$' == c || '@' == c || 0x03 == c || 0x11 == c || 0x13 == c)
745
            c = (unsigned char) '*';
746
        data_out[i] = c;
747
    }
748
 
749
    // Do checksum.
750
    crc = DoCRC(data_out, size);
751
 
752
    // Send checksum to target.
753
    SendChecksum(pSer, crc);
754
 
755
    // Give the target 1/10th of a sec to digest it
756
    CeCosThreadUtils::Sleep(100);
757
 
758
    switch (mode) {
759
    case MODE_NO_ECHO:
760
    {
761
        // Simple transmit. Don't expect target to echo data back.
762
        TargetWrite(pSer, data_out, size);
763
        ReceiveDone(pSer, NULL, 0);
764
    }
765
    break;
766
    case MODE_EOP_ECHO:
767
    {
768
        int in_crc;
769
 
770
        TargetWrite(pSer, data_out, size);
771
        Trace("Finished write, waiting for target echo.\n");
772
 
773
        // Expect target to echo the data
774
        TargetRead(pSer, data_in, size);
775
 
776
        // Check echoed data, and reply OK/ER accordingly.
777
        in_crc = DoCRC(data_in, size);
778
        SendStatus(pSer, (in_crc == crc));
779
 
780
 
781
        // Dump seen/expected on console.
782
        if (in_crc != crc) {
783
            Trace("Data seen:\n");
784
            PrintHex(data_in, size);
785
            Trace("<end>\n");
786
            Trace("Data expected:\n");
787
            PrintHex(data_out, size);
788
            Trace("<end>\n");
789
        }
790
 
791
        ReceiveDone(pSer, data_in, size);
792
 
793
    }
794
    break;
795
    case MODE_DUPLEX_ECHO:
796
    {
797
        int block_size = 64;
798
        int fail, j;
799
 
800
        // This is a simple implementation (maybe too simple).
801
        // Host sends 4 packets with the same size (64 bytes atm).
802
        // Target echoes in this way:
803
        //  packet1 -> packet1
804
        //  packet2 -> packet2, packet2
805
        //  packet3 -> packet3
806
        //  packet4 -> /dev/null
807
        //
808
        // The reads/writes are interleaved in a way that should ensure
809
        // the target out buffer to be full before the target starts to read
810
        // packet3. That is, the target should be both receiving (packet3)
811
        // and sending (packet2) at the same time.
812
 
813
        // This code needs restructuring. It's not very obvious what's
814
        // happening: The same block of data is output several times,
815
        // the target echoes the data back (one of the blocks is
816
        // echoed twice). Then the echoed data is compared agains the
817
        // outgoing data block.
818
 
819
        fail = 0;
820
        while (loop_count--) {
821
            int i;
822
            for (i = 0; i < block_size*4; i++)
823
                data_in[i] = 0;
824
 
825
            // out1: block_size -> block_size
826
            TargetWrite(pSer, data_out, block_size);
827
 
828
            // out2: block_size -> 2 x block_size
829
            TargetWrite(pSer, data_out, block_size);
830
 
831
            // in1:
832
            TargetRead(pSer, data_in, block_size);
833
 
834
            // out3: block_size -> block_size
835
            TargetWrite(pSer, data_out, block_size);
836
 
837
            // in2:
838
            TargetRead(pSer, &data_in[block_size], 2*block_size);
839
 
840
            // out4: block_size -> 0
841
            TargetWrite(pSer, data_out, block_size);
842
 
843
            // in3:
844
            TargetRead(pSer, &data_in[block_size*3], block_size);
845
 
846
            if (0 == loop_count % 10)
847
                Trace("%d loops to go\n", loop_count);
848
 
849
            // Verify data.
850
            if (!fail) {
851
                for (j = 0; j < 4 && !fail; j++) {
852
                    for (i = 0; i < block_size && !fail; i++) {
853
                        if (data_out[i] != data_in[j*block_size + i]) {
854
                            fail = 1;
855
                            Trace("Failed at byte %d\n", j*block_size + i);
856
 
857
                            Trace("Data seen:\n");
858
                            PrintHex(&data_in[j*block_size],
859
                                           block_size);
860
                            Trace("<end>\n");
861
                            Trace("Data expected:\n");
862
                            PrintHex(data_out, block_size);
863
                            Trace("<end>\n");
864
                        }
865
                    }
866
                }
867
            }
868
        }
869
        // Check echoed data, and reply OK/ER accordingly.
870
        SendStatus(pSer, (!fail));
871
        ReceiveDone(pSer, data_in, block_size*4);
872
    }
873
    break;
874
    default:
875
        Trace("Unknown mode. Ignoring.\n");
876
    }
877
 
878
    // Free buffer.
879
    free(data_in);
880
    free(data_out);
881
}
882
 
883
//-----------------------------------------------------------------------------
884
// Test transformations on text transmissions
885
//
886
// This test transmits null-terminated C strings back and forth. Since
887
// the translation is under test and may fail, the length of the data is
888
// (potentially) unknown. Sending with a null-terminator allows proper
889
// recovery even if the translations do not work as intended.
890
//
891
// Format in:
892
//  <flags>!<4 bytes binary checksum><C string>
893
// Format out:
894
//  <C string>
895
//  OK/ER
896
//
897
// Mode:
898
//   MODE_EOP_ECHO:
899
//       Receive data, verify CRC, resend data.
900
//       Send OK/ER reply when done.
901
//   MODE_DUPLEX_ECHO:
902
//       Receive data, echo data, verify CRC.
903
//       Send OK/ER reply when done.
904
//
905
// To Do:
906
//  Implement.
907
void
908
CeCosTestSerialFilter::CMD_TestText(CeCosSerial &pSer, char* /*args*/)
909
{
910
    SendStatus(pSer, 1);
911
}
912
 
913
//-----------------------------------------------------------------------------
914
// Reply to PING packet from target.
915
// Format in:
916
//  "!"
917
// Format out:
918
//  OK
919
void
920
CeCosTestSerialFilter::CMD_TestPing(CeCosSerial &pSer, char* /*args*/)
921
{
922
    SendStatus(pSer, 1);
923
}
924
 
925
//-----------------------------------------------------------------------------
926
// Dispatch test command. 
927
void
928
CeCosTestSerialFilter::DispatchCommand(CeCosSerial &pSer, char* cmd)
929
{
930
    char* args;
931
 
932
    args = strchr(cmd, (int) ':');
933
    if (!args) {
934
        Trace("Bogus command (%s) Ignoring.\n", cmd);
935
        return;
936
    }
937
 
938
    *args++ = 0;
939
 
940
    Trace("Dispatching command %s.\n", cmd);
941
 
942
    if (0 == strcmp("CONFIG", cmd)) {
943
        CMD_ChangeConfig(pSer, args);
944
    }
945
    else if (0 == strcmp("DEFCONFIG", cmd)) {
946
        // Note: Currently the arguments are ignored. 9600 8N1 is default.
947
        CMD_DefaultConfig(pSer);
948
    }
949
    else if (0 == strcmp("BINARY", cmd)) {
950
        CMD_TestBinary(pSer, args);
951
    }
952
    else if (0 == strcmp("TEXT", cmd)) {
953
        CMD_TestText(pSer, args);
954
    }
955
    else if (0 == strcmp("PING", cmd)) {
956
        CMD_TestPing(pSer, args);
957
    }
958
    else
959
        Trace("Unknown command '%s'.\n", cmd);
960
 
961
    Trace("Command %s completed.\n", cmd);
962
}
963
 
964
bool CALLBACK
965
SerialFilterFunction(void*& pBuf,
966
                     unsigned int& nRead,
967
                     CeCosSerial& serial,
968
                     CeCosSocket& socket,
969
                     void* pParem)
970
{
971
    CeCosTestSerialFilter* p = (CeCosTestSerialFilter*) pParem;
972
    return p->FilterFunctionProper(pBuf, nRead, serial, socket);
973
}
974
 
975
bool
976
CeCosTestSerialFilter::FilterFunctionProper(void*& pBuf,
977
                                            unsigned int& nRead,
978
                                            CeCosSerial& serial,
979
                                            CeCosSocket& socket)
980
{
981
    char* buffer = (char*) pBuf;
982
 
983
    // Don't do anything in the null filter mode.
984
    if (m_bNullFilter)
985
        return true;
986
 
987
    // Allows trace to be called without a reference to the socket...
988
    m_cGDBSocket = &socket;
989
 
990
    // Put in trace buffer in case we have to leave it because the packet
991
    // is incomplete
992
    m_xStoredTraceBuffer = (unsigned char *)
993
        realloc( m_xStoredTraceBuffer, m_nStoredTraceBufferSize + nRead );
994
    if ( NULL == m_xStoredTraceBuffer )
995
        throw "Could not allocate stored trace buffer";
996
    memcpy( m_xStoredTraceBuffer + m_nStoredTraceBufferSize, buffer, nRead );
997
    m_nStoredTraceBufferSize += nRead;
998
 
999
    // Now search for distinct packets, delimited by '@' (filter commands)
1000
    // and '$' (GDB packets)
1001
    unsigned int i, newStart=0;
1002
    for (i=0; i<m_nStoredTraceBufferSize; i++) {
1003
        if ( m_xStoredTraceBuffer[i] == '@' ||
1004
             m_xStoredTraceBuffer[i] == '$' ) {
1005
            if (m_bOptSerDebug &&
1006
                (m_bOptConsoleOutput || m_bFirstCommandSeen)) {
1007
 
1008
                // Output the serial data if option enabled - but only if
1009
                // dumping state to the console or after the first command
1010
                // has been seen from the filter. GDB gets confused by
1011
                // O-packets if they appear when it's trying to connect.
1012
 
1013
                PrintHex(&m_xStoredTraceBuffer[newStart], i - newStart);
1014
            }
1015
            newStart = i;
1016
        }
1017
    }
1018
 
1019
    // If we managed to print output, rejig the buffer size, and shunt
1020
    // the new start of the data to the front of the trace buffer
1021
    m_nStoredTraceBufferSize -= newStart;
1022
 
1023
    memmove( m_xStoredTraceBuffer, &m_xStoredTraceBuffer[newStart],
1024
             m_nStoredTraceBufferSize );
1025
 
1026
 
1027
    // Command handling.
1028
    // If we are not presently reading a command, look for the
1029
    // start marker.
1030
    i = 0;
1031
    if (!m_bCmdFlag)
1032
        for (; i < nRead; i++) {
1033
            if ('@' == buffer[i]) {
1034
                m_bCmdFlag = true;
1035
                // Send the data before the marker.
1036
                if (i)
1037
                    socket.send(buffer, i);
1038
                break;
1039
            }
1040
        }
1041
 
1042
    // If reading a command, look for the end marker.
1043
    if (m_bCmdFlag) {
1044
        char c = 0;
1045
        while (i < nRead && m_nCmdIndex < MAX_CMD_LEN) {
1046
            c = buffer[i++];
1047
            m_aCmd[m_nCmdIndex++] = c;
1048
            if ('!' == c) {
1049
                if (i != nRead) {
1050
                    m_nUnreadBufferIndex = 0;
1051
                    m_nUnreadBufferSize = nRead - i;
1052
                    m_xUnreadBuffer =
1053
                        (unsigned char*) malloc(m_nUnreadBufferSize);
1054
                    if (!m_xUnreadBuffer) {
1055
                        m_nUnreadBufferSize = 0;
1056
                        throw "Could not allocate unread buffer!";
1057
                    }
1058
 
1059
                    int ix = 0;
1060
                    while (i < nRead)
1061
                        m_xUnreadBuffer[ix++] = buffer[i++];
1062
                }
1063
                break;
1064
            }
1065
        }
1066
 
1067
        if (MAX_CMD_LEN == m_nCmdIndex) {
1068
            Trace("Received too long command. Ignoring it!\n");
1069
            m_nCmdIndex = 0;
1070
            m_bCmdFlag = false;
1071
        } else if ('!' == c) {
1072
            // Was the command completed?
1073
            m_aCmd[m_nCmdIndex - 1] = 0;// terminate cmd
1074
            m_nCmdIndex = 0;
1075
            m_bCmdFlag = false;
1076
 
1077
            // First command dispatched. Initialize serial to nonblocking.
1078
            if (!m_bFirstCommandSeen) {
1079
                m_bFirstCommandSeen = true;
1080
                serial.SetBlockingReads(false);
1081
            }
1082
 
1083
            try {
1084
                // skip @ when passing ptr
1085
                DispatchCommand(serial, &m_aCmd[1]);
1086
            }
1087
            catch (filter_abort_t* msg) {
1088
                // This allows the filter to unwind, wherever in the
1089
                // protocol it may be, when a $ is detected from the
1090
                // target side.  When this happens, we may have a
1091
                // trap/exception on the target and we want the user
1092
                // to access the target via GDB without intervention.
1093
 
1094
                // Do nothing from next call.
1095
                m_bNullFilter = true;
1096
 
1097
                // Copy the start of the $-packet to the inbuffer.
1098
                unsigned char *d = (unsigned char*) pBuf;
1099
                const unsigned char *s = msg->data_ptr;
1100
                unsigned int len = msg->data_len;
1101
 
1102
                // It should be possible to re-allocate buffer. Didn't seem
1103
                // to work properly though. Probably won't be a problem
1104
                // since we would normally only see 1-2 bytes of the
1105
                // $-packet anyway.
1106
                if (len > nRead)
1107
                    throw "Not enough room for $-message";
1108
 
1109
                while (len--)
1110
                    *d++ = *s++;
1111
 
1112
                nRead = msg->data_len;
1113
 
1114
                delete msg;
1115
 
1116
                return true;
1117
            }
1118
        }
1119
 
1120
        nRead = 0;                      // Never leave anything for caller
1121
                                        // This is a violation of the intended
1122
                                        // filter function behavior.
1123
    }
1124
    return true;
1125
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.