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

Subversion Repositories openrisc

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

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
//        eCosTestDownloadFilter.cpp
28
//
29
//        Socket/serial download filter class
30
//
31
//=================================================================
32
//=================================================================
33
//#####DESCRIPTIONBEGIN####
34
//
35
// Author(s):     jskov
36
// Contributors:  jskov
37
// Date:          1999-09-20
38
 
39
// Description:   This filter sits between the (farm) host's socket and
40
 
41
//                the serial connection to the target board. The
42
//                filter listens for special download packets from the
43
//                client using the board. The download packet allows
44
//                the relative slow GDB download protocol to be restricted
45
//                to the connection between the farm host and the board.
46
//                This prevents slow downloads due to long round-trip times
47
//                and TCP packets with only a few bytes in them.
48
// To Do:
49
//  o Move parts shared between eCosTestDownloadFilter and eCosTestSerialFilter
50
//    into a shared class.
51
//####DESCRIPTIONEND####
52
 
53
#include "eCosStd.h"
54
#include "eCosTrace.h"
55
 
56
#include "eCosTestDownloadFilter.h"
57
 
58
CeCosTestDownloadFilter::CeCosTestDownloadFilter():
59
    m_bNullFilter(false), m_bOptSerDebug(false), m_bOptFilterTrace(false),
60
    m_nCmdIndex(0), m_bCmdFlag(false), m_bContinueSession(false)
61
{
62
}
63
 
64
CeCosTestDownloadFilter::~CeCosTestDownloadFilter()
65
{
66
}
67
 
68
//------------------------
69
// Output helpers.
70
 
71
void
72
CeCosTestDownloadFilter::ConsoleWrite(const char* pszStr)
73
{
74
    fputs(pszStr, stderr);
75
    fflush(stderr);
76
}
77
 
78
void
79
CeCosTestDownloadFilter::Trace(const char* pszFormat, ...)
80
{
81
  va_list marker;
82
  va_start (marker, pszFormat);
83
 
84
  for(int nLength=100;nLength;) {
85
    char *buf=new char[1+nLength];
86
    int n=vsnprintf(buf+4, nLength-4, pszFormat, marker );
87
    if(-1==n){
88
      nLength*=2;  // NT behavior
89
    } else if (n<nLength){
90
      memcpy(buf,"[d] ",4);
91
      ConsoleWrite(buf);
92
      nLength=0;   // trigger exit from loop
93
    } else {
94
      nLength=n+1; // UNIX behavior generally, or NT behavior when buffer size exactly matches required length
95
    }
96
    delete [] buf;
97
  }
98
 
99
  va_end (marker);
100
}
101
 
102
void
103
CeCosTestDownloadFilter::PrintHex(const unsigned char* d1, int len, data_origin_t origin/*=SF_TARGET*/)
104
{
105
    int offset = 0;
106
    int i;
107
    char buf[128];
108
    int width = 8;
109
 
110
    while (len) {
111
        int count = MIN(width, len);
112
        char* p = buf;
113
        switch (origin) {
114
        case SF_TARGET:
115
            p += sprintf(p, "T");
116
            break;
117
        case SF_FILTER:
118
            p += sprintf(p, "F");
119
            break;
120
        }
121
        p += sprintf(p, ":%04x ", offset);
122
        // Print hex values.
123
        for (i = 0; i < count; i++)
124
            p += sprintf(p, "%02x ", d1[i]);
125
        for (     ; i < width   ; i++)
126
            p += sprintf(p, ".. ");
127
 
128
        // Print ASCII string
129
        p += sprintf(p, "'");
130
        for (i = 0; i < count; i++) {
131
            int c = d1[i];
132
            if (' ' >= c || 'z' <= c)
133
                c = '.';
134
            p += sprintf(p, "%c", c);
135
        }
136
        sprintf(p, "'\n");
137
 
138
        Trace("%s", buf);
139
 
140
        len -= count;
141
        offset += count;
142
        d1 += count;
143
    }
144
}
145
 
146
void
147
CeCosTestDownloadFilter::TargetWrite(CeCosSerial &pSer,
148
                                    const unsigned char* buffer, int len)
149
{
150
    unsigned int __written;
151
 
152
    if (m_bOptSerDebug)
153
        PrintHex(buffer, len, SF_FILTER);
154
 
155
    do {
156
        if (!(pSer.Write((void*) buffer, len, __written))) {
157
            fprintf(stderr, "Writing %d bytes to serial failed\n", len);
158
            fprintf(stderr, "%s", (LPCTSTR)pSer.ErrString());
159
            throw _T("serial write failed");
160
        }
161
        buffer += __written;
162
        len -= __written;
163
    } while (len);
164
}
165
 
166
// Snuffed from gdb/remote.c
167
int
168
CeCosTestDownloadFilter::tohex (int nib)
169
{
170
    if (nib < 10)
171
        return '0'+nib;
172
    else
173
        return 'a'+nib-10;
174
}
175
 
176
int
177
CeCosTestDownloadFilter::hexnumstr (unsigned char* buf, unsigned long num)
178
{
179
  int i;
180
  unsigned long num2 = num;
181
 
182
  for (i = 0; num2 != 0; i++)
183
    num2 >>= 4;
184
 
185
  int len = MAX (i, 1);
186
 
187
  buf[len] = '\0';
188
 
189
  for (i = len - 1; i >= 0; i--)
190
    {
191
      buf[i] = "0123456789abcdef" [(num & 0xf)];
192
      num >>= 4;
193
    }
194
 
195
  return len;
196
}
197
 
198
int
199
CeCosTestDownloadFilter::hexnumlen (unsigned long num)
200
{
201
  int i;
202
  unsigned long num2 = num;
203
 
204
  for (i = 0; num2 != 0; i++)
205
    num2 >>= 4;
206
 
207
  return MAX (i, 1);
208
}
209
 
210
// Based on routines in gdb/remote.c
211
int
212
CeCosTestDownloadFilter::put_binary (unsigned char* buf, int len,
213
                                     unsigned long dl_address,
214
                                     int packet_size,
215
                                     CeCosSerial& serial)
216
{
217
    int i;
218
    unsigned char csum;
219
    Buffer buf2(packet_size);
220
    unsigned char ch;
221
    int tcount = 0;
222
    unsigned char *p, *p2, *plen;
223
 
224
    while (len > 0) {
225
        /* Subtract header overhead from MAX payload size:
226
           $M<memaddr>,<len>:#nn */
227
        int max_buf_size =
228
            buf2.Size()
229
            - ( 2 + hexnumlen(dl_address) + 1 + hexnumlen(buf2.Size()) + 4);
230
 
231
        /* Copy the packet into buffer BUF2, encapsulating it
232
           and giving it a checksum.  */
233
        int todo = MIN (len, max_buf_size);
234
 
235
        p = (unsigned char*) buf2.Data();
236
        *p++ = '$';
237
 
238
        // Add X header.
239
        *p++ = 'X';
240
        p += hexnumstr(p, dl_address);
241
        *p++ = ',';
242
        plen = p;                       /* remember where len field goes */
243
        p += hexnumstr(p, todo);
244
        *p++ = ':';
245
 
246
        int escaped = 0;
247
        for (i = 0;
248
             (i < todo) && (i + escaped) < (max_buf_size - 2);
249
             i++)
250
        {
251
            switch (buf[i] & 0xff)
252
            {
253
            case '$':
254
            case '#':
255
            case 0x7d:
256
                /* These must be escaped */
257
                escaped++;
258
                *p++ = 0x7d;
259
                *p++ = (unsigned char) ((buf[i] & 0xff) ^ 0x20);
260
                break;
261
            default:
262
                *p++ = (unsigned char) (buf[i] & 0xff);
263
                break;
264
            }
265
        }
266
 
267
        if (i < todo)
268
        {
269
            /* Escape chars have filled up the buffer prematurely,
270
               and we have actually sent fewer bytes than planned.
271
               Fix-up the length field of the packet.  */
272
 
273
            /* FIXME: will fail if new len is a shorter string than
274
               old len.  */
275
 
276
            plen += hexnumstr (plen, i);
277
            *plen++ = ':';
278
        }
279
 
280
        // Calculate checksum
281
        p2 = (unsigned char*)buf2.Data();
282
        p2++; // skip $
283
        csum = 0;
284
        while (p2 < p)
285
            csum = (unsigned char)(csum + *p2++);
286
        *p++ = '#';
287
        *p++ = (unsigned char) tohex ((csum >> 4) & 0xf);
288
        *p++ = (unsigned char) tohex (csum & 0xf);
289
 
290
        /* Send it over and over until we get a positive ack.  */
291
 
292
        int resend = 1;
293
        const unsigned char* write_ptr = (const unsigned char*) buf2.Data();
294
        int write_len = (int)p-(int)buf2.Data();
295
        while (resend)
296
        {
297
            unsigned int __written;
298
 
299
            Trace("Sending bytes for %p-%p\n", dl_address, dl_address+i);
300
            TargetWrite(serial, write_ptr, write_len);
301
 
302
            /* read until either a timeout occurs (-2) or '+' is read */
303
            for(;;)
304
            {
305
                unsigned int __read;
306
                serial.Read(&ch, 1, __read);
307
 
308
                if (0 == __read) {
309
                    tcount ++;
310
                    if (tcount > 3) {
311
                        Trace("Timeout in putpkt_binary\n");
312
                        return 0;
313
                    }
314
                    break;              /* Retransmit buffer */
315
                }
316
 
317
                switch (ch)
318
                {
319
                case '+':
320
                    // Now expect OK packet from target
321
                    unsigned char ok_msg[6];// $OK#9a
322
                    serial.Read(ok_msg, 6, __read);
323
 
324
                    // Reply with ACK
325
                    serial.Write((void*)"+", 1, __written);
326
 
327
                    // And process next packet.
328
                    resend = 0;
329
                    break;
330
 
331
                case '-':
332
                    // Bad packet CRC. Retransmit.
333
                    Trace ("Bad CRC\n");
334
                    break;
335
 
336
                default:
337
                    Trace("Got junk..%02x\n", ch);
338
                    continue;           // keep reading
339
                }
340
                break;          /* Here to retransmit */
341
            }
342
        }
343
 
344
        len -= i;
345
        dl_address += i;
346
        buf += i;
347
    }
348
 
349
    return 1;
350
}
351
 
352
bool CALLBACK
353
DownloadFilterFunction(void*& pBuf,
354
                       unsigned int& nRead,
355
                       CeCosSerial& serial,
356
                       CeCosSocket& socket,
357
                       void* pParem)
358
{
359
    CeCosTestDownloadFilter* p = (CeCosTestDownloadFilter*) pParem;
360
    bool res = false;
361
 
362
    try {
363
        res = p->FilterFunctionProper(pBuf, nRead, serial, socket);
364
    }
365
    catch (LPCTSTR s) {
366
        TRACE(_T("Download filter caught string: %s\n"), s);
367
    }
368
    catch (...) {
369
        TRACE(_T("Download filter caught unknown exception\n"));
370
    }
371
 
372
    return res;
373
}
374
 
375
bool
376
CeCosTestDownloadFilter::FilterFunctionProper(void*& pBuf,
377
                                              unsigned int& nRead,
378
                                              CeCosSerial& serial,
379
                                              CeCosSocket& socket)
380
{
381
    char* buffer = (char*) pBuf;
382
 
383
    // Assume the worst - don't allow session to continue until a successful
384
    // download.
385
    m_bContinueSession = false;
386
 
387
    // Output the serial data if option enabled
388
    if (m_bOptSerDebug)
389
        PrintHex((unsigned char*) buffer, nRead);
390
 
391
    // Stop here if in NULL-filter mode
392
    if (m_bNullFilter)
393
        return true;
394
 
395
    // Command handling.
396
    // Be strict here; very first byte we see must be the start marker,
397
    // else go into NULL-filter mode
398
    unsigned int i = 0;
399
    if (!m_bCmdFlag) {
400
        if ('@' != buffer[i]) {
401
            m_bNullFilter = true;
402
            return true;
403
        }
404
        m_bCmdFlag = true;
405
    }
406
 
407
    // If reading a command, look for the end marker.
408
    if (m_bCmdFlag) {
409
        char c = 0;
410
        while (i < nRead && m_nCmdIndex < MAX_CMD_LEN) {
411
            c = buffer[i++];
412
            m_aCmd[m_nCmdIndex++] = c;
413
            if ('!' == c) {
414
                if (i != nRead) {
415
                    throw _T("Extra bytes after command packet!?!");
416
                }
417
            }
418
        }
419
 
420
        if (MAX_CMD_LEN == m_nCmdIndex) {
421
            Trace("Received too long command. Ignoring it!\n");
422
            m_nCmdIndex = 0;
423
            m_bCmdFlag = false;
424
        } else if ('!' == c) {
425
            // Was the command completed?
426
            m_aCmd[m_nCmdIndex - 1] = 0;// terminate cmd
427
            m_nCmdIndex = 0;
428
            m_bCmdFlag = false;
429
            // command now in m_aCmd[]
430
 
431
            Trace("Got command %s\n", m_aCmd);
432
 
433
            // After this, never interfere.
434
            m_bNullFilter = true;
435
 
436
            // Get arguments: @<length>:<dl_address>:<start_address>!
437
            int length, packet_size;
438
            unsigned long dl_addr, start_addr;
439
            INIT_VALUE(&m_aCmd[1]);
440
            SET_VALUE(int, length);
441
            SET_VALUE(unsigned long, dl_addr);
442
            SET_VALUE(unsigned long, start_addr);
443
            SET_VALUE(int, packet_size);
444
 
445
            Trace("len %d, dl %08x, start %08x, packet_size %d\n",
446
                  length, dl_addr, start_addr, packet_size);
447
 
448
            // Reply so host will send file.
449
            socket.send("@", 1);
450
 
451
            // Read file from host
452
            Buffer buf(length);
453
            if (socket.recv(buf.Data(), length)) {
454
 
455
                // Remember old blocking state, and set serial to
456
                // blocking reads.
457
                bool __blocking = serial.GetBlockingReads();
458
                serial.SetBlockingReads(true);
459
                serial.Flush();
460
 
461
                // Send + to target, acking whatever packet was pending
462
                unsigned int __written = 0;
463
                serial.Write((void*)"+", 1, __written);
464
 
465
                // Convert to packets and transfer to target.
466
                if (put_binary((unsigned char*) buf.Data(),
467
                               length, dl_addr, packet_size, serial)) {
468
                    // Send detach signal to target
469
                    unsigned char ch;
470
                    unsigned int __read;
471
                    serial.Write((void*)"$D#44", 5, __written);
472
                    serial.Read(&ch, 1, __read);
473
 
474
                    // Reply to host marking end of download
475
                    socket.send("+", 1);
476
 
477
                    // Let server know it's OK to accept another connection
478
                    // in this session.
479
                    m_bContinueSession = true;
480
                } else {
481
                    // Reply to host marking failed download
482
                    socket.send("-", 1);
483
                }
484
 
485
                // Reset previous blocking mode
486
                serial.SetBlockingReads(__blocking);
487
 
488
            } else {
489
                // Reply to host marking failed file transfer
490
                socket.send("?", 1);
491
            }
492
        }
493
        nRead = 0;                      // Never leave anything for caller
494
                                        // This is a violation of the intended
495
                                        // filter function behavior.
496
    }
497
    return true;
498
}

powered by: WebSVN 2.1.0

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