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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [tools/] [src/] [tools/] [ecostest/] [common/] [eCosTestSerialFilter.cpp] - Blame information for rev 592

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

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

powered by: WebSVN 2.1.0

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