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

Subversion Repositories openrisc

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

powered by: WebSVN 2.1.0

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