Statistics
| Branch: | Tag: | Revision:

mongoose / examples / nRF52 / http / rtt / RTT / SEGGER_RTT.c @ eaef5bd1

History | View | Annotate | Download (18.8 KB)

1
/* clang-format off */
2
/*********************************************************************
3
*              SEGGER MICROCONTROLLER GmbH & Co. KG                  *
4
*        Solutions for real time microcontroller applications        *
5
**********************************************************************
6
*                                                                    *
7
*        (c) 2014-2014 SEGGER Microcontroller GmbH & Co. KG          *
8
*                                                                    *
9
*       Internet: www.segger.com Support: support@segger.com         *
10
*                                                                    *
11
**********************************************************************
12
----------------------------------------------------------------------
13
File    : SEGGER_RTT.c
14
Date    : 17 Dec 2014
15
Purpose : Implementation of SEGGER real-time terminal (RTT) which allows
16
          real-time terminal communication on targets which support
17
          debugger memory accesses while the CPU is running.
18

19
          Type "int" is assumed to be 32-bits in size
20
          H->T    Host to target communication
21
          T->H    Target to host communication
22

23
          RTT channel 0 is always present and reserved for Terminal usage.
24
          Name is fixed to "Terminal"
25

26
---------------------------END-OF-HEADER------------------------------
27
*/
28

    
29
#include "SEGGER_RTT_Conf.h"
30
#include "SEGGER_RTT.h"
31

    
32
#include <string.h>                 // for memcpy
33

    
34
/*********************************************************************
35
*
36
*       Defines, configurable
37
*
38
**********************************************************************
39
*/
40

    
41
#ifndef   BUFFER_SIZE_UP
42
  #define BUFFER_SIZE_UP                                  (1024)  // Size of the buffer for terminal output of target, up to host
43
#endif
44

    
45
#ifndef   BUFFER_SIZE_DOWN
46
  #define BUFFER_SIZE_DOWN                                (16)    // Size of the buffer for terminal input to target from host (Usually keyboard input)
47
#endif
48

    
49
#ifndef   SEGGER_RTT_MAX_NUM_UP_BUFFERS
50
  #define SEGGER_RTT_MAX_NUM_UP_BUFFERS                   (1)     // Number of up-buffers (T->H) available on this target
51
#endif
52

    
53
#ifndef   SEGGER_RTT_MAX_NUM_DOWN_BUFFERS
54
  #define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS                 (1)     // Number of down-buffers (H->T) available on this target
55
#endif
56

    
57
#ifndef   SEGGER_RTT_LOCK
58
  #define SEGGER_RTT_LOCK()
59
#endif
60

    
61
#ifndef   SEGGER_RTT_UNLOCK
62
  #define SEGGER_RTT_UNLOCK()
63
#endif
64

    
65
#ifndef   SEGGER_RTT_IN_RAM
66
  #define SEGGER_RTT_IN_RAM                               (0)
67
#endif
68

    
69
/*********************************************************************
70
*
71
*       Defines, fixed
72
*
73
**********************************************************************
74
*/
75

    
76
#define MIN(a, b)        (((a) < (b)) ? (a) : (b))
77
#define MAX(a, b)        (((a) > (b)) ? (a) : (b))
78

    
79
#define MEMCPY(a, b, c)  memcpy((a),(b),(c))
80

    
81
//
82
// For some environments, NULL may not be defined until certain headers are included
83
//
84
#ifndef NULL
85
  #define NULL 0
86
#endif
87

    
88
/*********************************************************************
89
*
90
*       Types
91
*
92
**********************************************************************
93
*/
94

    
95
//
96
// Description for a circular buffer (also called "ring buffer")
97
// which is used as up- (T->H) or down-buffer (H->T)
98
//
99
typedef struct {
100
  const char* sName;                     // Optional name. Standard names so far are: "Terminal", "VCom"
101
  char*  pBuffer;                        // Pointer to start of buffer
102
  int    SizeOfBuffer;                   // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
103
  volatile int WrOff;                    // Position of next item to be written by either host (down-buffer) or target (up-buffer). Must be volatile since it may be modified by host (down-buffer)
104
  volatile int RdOff;                    // Position of next item to be read by target (down-buffer) or host (up-buffer). Must be volatile since it may be modified by host (up-buffer)
105
  int    Flags;                          // Contains configuration flags
106
} RING_BUFFER;
107

    
108
//
109
// RTT control block which describes the number of buffers available
110
// as well as the configuration for each buffer
111
//
112
//
113
typedef struct {
114
  char        acID[16];                                 // Initialized to "SEGGER RTT"
115
  int         MaxNumUpBuffers;                          // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2)
116
  int         MaxNumDownBuffers;                        // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2)
117
  RING_BUFFER aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS];       // Up buffers, transferring information up from target via debug probe to host
118
  RING_BUFFER aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS];   // Down buffers, transferring information down from host via debug probe to target
119
} SEGGER_RTT_CB;
120

    
121
/*********************************************************************
122
*
123
*       Static data
124
*
125
**********************************************************************
126
*/
127
//
128
// Allocate buffers for channel 0
129
//
130
static char _acUpBuffer  [BUFFER_SIZE_UP];
131
static char _acDownBuffer[BUFFER_SIZE_DOWN];
132
//
133
// Initialize SEGGER Real-time-Terminal control block (CB)
134
//
135
static SEGGER_RTT_CB _SEGGER_RTT = {
136
#if SEGGER_RTT_IN_RAM
137
  "SEGGER RTTI",
138
#else
139
  "SEGGER RTT",
140
#endif
141
  SEGGER_RTT_MAX_NUM_UP_BUFFERS,
142
  SEGGER_RTT_MAX_NUM_DOWN_BUFFERS,
143
  {{ "Terminal", &_acUpBuffer[0],   sizeof(_acUpBuffer),   0, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP }},
144
  {{ "Terminal", &_acDownBuffer[0], sizeof(_acDownBuffer), 0, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP }},
145
};
146

    
147
static char _ActiveTerminal;
148

    
149
/*********************************************************************
150
*
151
*       Static code
152
*
153
**********************************************************************
154
*/
155

    
156
/*********************************************************************
157
*
158
*       _strlen
159
*
160
*  Function description
161
*    ANSI compatible function to determine the length of a string
162
*
163
*  Return value
164
*    Length of string in bytes.
165
*
166
*  Parameters
167
*    s         Pointer to \0 terminated string.
168
*
169
*  Notes
170
*    (1) s needs to point to an \0 terminated string. Otherwise proper functionality of this function is not guaranteed.
171
*/
172
static int _strlen(const char* s) {
173
  int Len;
174

    
175
  Len = 0;
176
  if (s == NULL) {
177
    return 0;
178
  }
179
  do {
180
    if (*s == 0) {
181
      break;
182
    }
183
    Len++;
184
    s++;
185
  } while (1);
186
  return Len;
187
}
188

    
189
/*********************************************************************
190
*
191
*       _Init
192
*
193
*  Function description
194
*    In case SEGGER_RTT_IN_RAM is defined,
195
*    _Init() modifies the ID of the RTT CB to allow identifying the
196
*    RTT Control Block Structure in the data segment.
197
*/
198
static void _Init(void) {
199
#if SEGGER_RTT_IN_RAM
200
  if (_SEGGER_RTT.acID[10] == 'I') {
201
    _SEGGER_RTT.acID[10] = '\0';
202
  }
203
#endif
204
}
205

    
206
/*********************************************************************
207
*
208
*       Public code
209
*
210
**********************************************************************
211
*/
212
/*********************************************************************
213
*
214
*       SEGGER_RTT_Read
215
*
216
*  Function description
217
*    Reads characters from SEGGER real-time-terminal control block
218
*    which have been previously stored by the host.
219
*
220
*  Parameters
221
*    BufferIndex  Index of Down-buffer to be used. (e.g. 0 for "Terminal")
222
*    pBuffer      Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to.
223
*    BufferSize   Size of the target application buffer
224
*
225
*  Return values
226
*    Number of bytes that have been read
227
*/
228
int SEGGER_RTT_Read(unsigned BufferIndex, char* pBuffer, unsigned BufferSize) {
229
  int NumBytesRem;
230
  unsigned NumBytesRead;
231
  int RdOff;
232
  int WrOff;
233

    
234
  SEGGER_RTT_LOCK();
235
  _Init();
236
  RdOff = _SEGGER_RTT.aDown[BufferIndex].RdOff;
237
  WrOff = _SEGGER_RTT.aDown[BufferIndex].WrOff;
238
  NumBytesRead = 0;
239
  //
240
  // Read from current read position to wrap-around of buffer, first
241
  //
242
  if (RdOff > WrOff) {
243
    NumBytesRem = _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer - RdOff;
244
    NumBytesRem = MIN(NumBytesRem, (int)BufferSize);
245
    MEMCPY(pBuffer, _SEGGER_RTT.aDown[BufferIndex].pBuffer + RdOff, NumBytesRem);
246
    NumBytesRead += NumBytesRem;
247
    pBuffer      += NumBytesRem;
248
    BufferSize   -= NumBytesRem;
249
    RdOff        += NumBytesRem;
250
    //
251
    // Handle wrap-around of buffer
252
    //
253
    if (RdOff == _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer) {
254
      RdOff = 0;
255
    }
256
  }
257
  //
258
  // Read remaining items of buffer
259
  //
260
  NumBytesRem = WrOff - RdOff;
261
  NumBytesRem = MIN(NumBytesRem, (int)BufferSize);
262
  if (NumBytesRem > 0) {
263
    MEMCPY(pBuffer, _SEGGER_RTT.aDown[BufferIndex].pBuffer + RdOff, NumBytesRem);
264
    NumBytesRead += NumBytesRem;
265
    pBuffer      += NumBytesRem;
266
    BufferSize   -= NumBytesRem;
267
    RdOff        += NumBytesRem;
268
  }
269
  if (NumBytesRead) {
270
    _SEGGER_RTT.aDown[BufferIndex].RdOff = RdOff;
271
  }
272
  SEGGER_RTT_UNLOCK();
273
  return NumBytesRead;
274
}
275

    
276
/*********************************************************************
277
*
278
*       SEGGER_RTT_Write
279
*
280
*  Function description
281
*    Stores a specified number of characters in SEGGER RTT
282
*    control block which is then read by the host.
283
*
284
*  Parameters
285
*    BufferIndex  Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
286
*    pBuffer      Pointer to character array. Does not need to point to a \0 terminated string.
287
*    NumBytes     Number of bytes to be stored in the SEGGER RTT control block.
288
*
289
*  Return values
290
*    Number of bytes which have been stored in the "Up"-buffer.
291
*
292
*  Notes
293
*    (1) If there is not enough space in the "Up"-buffer, remaining characters of pBuffer are dropped.
294
*/
295
int SEGGER_RTT_Write(unsigned BufferIndex, const char* pBuffer, unsigned NumBytes) {
296
  int NumBytesToWrite;
297
  unsigned NumBytesWritten;
298
  int RdOff;
299
  //
300
  // Target is not allowed to perform other RTT operations while string still has not been stored completely.
301
  // Otherwise we would probably end up with a mixed string in the buffer.
302
  //
303
  SEGGER_RTT_LOCK();
304
  _Init();
305
  //
306
  // In case we are not in blocking mode,
307
  // we need to calculate, how many bytes we can put into the buffer at all.
308
  //
309
  if ((_SEGGER_RTT.aUp[BufferIndex].Flags & SEGGER_RTT_MODE_MASK) != SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) {
310
    RdOff = _SEGGER_RTT.aUp[BufferIndex].RdOff;
311
    NumBytesToWrite =  RdOff - _SEGGER_RTT.aUp[BufferIndex].WrOff - 1;
312
    if (NumBytesToWrite < 0) {
313
      NumBytesToWrite += _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer;
314
    }
315
    //
316
    // If the complete data does not fit in the buffer, check if we have to skip it completely or trim the data
317
    //
318
    if ((int)NumBytes > NumBytesToWrite) {
319
      if ((_SEGGER_RTT.aUp[BufferIndex].Flags & SEGGER_RTT_MODE_MASK) == SEGGER_RTT_MODE_NO_BLOCK_SKIP) {
320
        SEGGER_RTT_UNLOCK();
321
        return 0;
322
      } else {
323
        NumBytes = NumBytesToWrite;
324
      }
325
    }
326
  }
327
  //
328
  // Early out if nothing is to do
329
  //
330
  if (NumBytes == 0) {
331
    SEGGER_RTT_UNLOCK();
332
    return 0;
333
  }
334
  //
335
  // Write data to buffer and handle wrap-around if necessary
336
  //
337
  NumBytesWritten = 0;
338
  do {
339
    RdOff = _SEGGER_RTT.aUp[BufferIndex].RdOff;                          // May be changed by host (debug probe) in the meantime
340
    NumBytesToWrite = RdOff - _SEGGER_RTT.aUp[BufferIndex].WrOff - 1;
341
    if (NumBytesToWrite < 0) {
342
      NumBytesToWrite += _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer;
343
    }
344
    NumBytesToWrite = MIN(NumBytesToWrite, (_SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer - _SEGGER_RTT.aUp[BufferIndex].WrOff));    // Number of bytes that can be written until buffer wrap-around
345
    NumBytesToWrite = MIN(NumBytesToWrite, (int)NumBytes);
346
    MEMCPY(_SEGGER_RTT.aUp[BufferIndex].pBuffer + _SEGGER_RTT.aUp[BufferIndex].WrOff, pBuffer, NumBytesToWrite);
347
    NumBytesWritten     += NumBytesToWrite;
348
    pBuffer             += NumBytesToWrite;
349
    NumBytes            -= NumBytesToWrite;
350
    _SEGGER_RTT.aUp[BufferIndex].WrOff += NumBytesToWrite;
351
    if (_SEGGER_RTT.aUp[BufferIndex].WrOff == _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer) {
352
      _SEGGER_RTT.aUp[BufferIndex].WrOff = 0;
353
    }
354
  } while (NumBytes);
355
  SEGGER_RTT_UNLOCK();
356
  return NumBytesWritten;
357
}
358

    
359
/*********************************************************************
360
*
361
*       SEGGER_RTT_WriteString
362
*
363
*  Function description
364
*    Stores string in SEGGER RTT control block.
365
*    This data is read by the host.
366
*
367
*  Parameters
368
*    BufferIndex  Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
369
*    s            Pointer to string.
370
*
371
*  Return values
372
*    Number of bytes which have been stored in the "Up"-buffer.
373
*
374
*  Notes
375
*    (1) If there is not enough space in the "Up"-buffer, depending on configuration,
376
*        remaining characters may be dropped or RTT module waits until there is more space in the buffer.
377
*    (2) String passed to this function has to be \0 terminated
378
*    (3) \0 termination character is *not* stored in RTT buffer
379
*/
380
int SEGGER_RTT_WriteString(unsigned BufferIndex, const char* s) {
381
  int Len;
382

    
383
  Len = _strlen(s);
384
  return SEGGER_RTT_Write(BufferIndex, s, Len);
385
}
386

    
387
/*********************************************************************
388
*
389
*       SEGGER_RTT_GetKey
390
*
391
*  Function description
392
*    Reads one character from the SEGGER RTT buffer.
393
*    Host has previously stored data there.
394
*
395
*  Return values
396
*    <  0    No character available (buffer empty).
397
*    >= 0    Character which has been read. (Possible values: 0 - 255)
398
*
399
*  Notes
400
*    (1) This function is only specified for accesses to RTT buffer 0.
401
*/
402
int SEGGER_RTT_GetKey(void) {
403
  char c;
404
  int r;
405

    
406
  r = SEGGER_RTT_Read(0, &c, 1);
407
  if (r == 1) {
408
    return (int)(unsigned char)c;
409
  }
410
  return -1;
411
}
412

    
413
/*********************************************************************
414
*
415
*       SEGGER_RTT_WaitKey
416
*
417
*  Function description
418
*    Waits until at least one character is avaible in the SEGGER RTT buffer.
419
*    Once a character is available, it is read and this function returns.
420
*
421
*  Return values
422
*    >=0    Character which has been read.
423
*
424
*  Notes
425
*    (1) This function is only specified for accesses to RTT buffer 0
426
*    (2) This function is blocking if no character is present in RTT buffer
427
*/
428
int SEGGER_RTT_WaitKey(void) {
429
  int r;
430

    
431
  do {
432
    r = SEGGER_RTT_GetKey();
433
  } while (r < 0);
434
  return r;
435
}
436

    
437
/*********************************************************************
438
*
439
*       SEGGER_RTT_HasKey
440
*
441
*  Function description
442
*    Checks if at least one character for reading is available in the SEGGER RTT buffer.
443
*
444
*  Return values
445
*    0      No characters are available to read.
446
*    1      At least one character is available.
447
*
448
*  Notes
449
*    (1) This function is only specified for accesses to RTT buffer 0
450
*/
451
int SEGGER_RTT_HasKey(void) {
452
  int RdOff;
453

    
454
  _Init();
455
  RdOff = _SEGGER_RTT.aDown[0].RdOff;
456
  if (RdOff != _SEGGER_RTT.aDown[0].WrOff) {
457
    return 1;
458
  }
459
  return 0;
460
}
461

    
462
/*********************************************************************
463
*
464
*       SEGGER_RTT_ConfigUpBuffer
465
*
466
*  Function description
467
*    Run-time configuration of a specific up-buffer (T->H).
468
*    Buffer to be configured is specified by index.
469
*    This includes: Buffer address, size, name, flags, ...
470
*
471
*  Return value
472
*    >= 0  O.K.
473
*     < 0  Error
474
*/
475
int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, char* pBuffer, int BufferSize, int Flags) {
476
  _Init();
477
  if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) {
478
    SEGGER_RTT_LOCK();
479
    if (BufferIndex > 0) {
480
      _SEGGER_RTT.aUp[BufferIndex].sName        = sName;
481
      _SEGGER_RTT.aUp[BufferIndex].pBuffer      = pBuffer;
482
      _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize;
483
      _SEGGER_RTT.aUp[BufferIndex].RdOff        = 0;
484
      _SEGGER_RTT.aUp[BufferIndex].WrOff        = 0;
485
    }
486
    _SEGGER_RTT.aUp[BufferIndex].Flags          = Flags;
487
    SEGGER_RTT_UNLOCK();
488
    return 0;
489
  }
490
  return -1;
491
}
492

    
493
/*********************************************************************
494
*
495
*       SEGGER_RTT_ConfigDownBuffer
496
*
497
*  Function description
498
*    Run-time configuration of a specific down-buffer (H->T).
499
*    Buffer to be configured is specified by index.
500
*    This includes: Buffer address, size, name, flags, ...
501
*
502
*  Return value
503
*    >= 0  O.K.
504
*     < 0  Error
505
*/
506
int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, char* pBuffer, int BufferSize, int Flags) {
507
  _Init();
508
  if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) {
509
    SEGGER_RTT_LOCK();
510
    if (BufferIndex > 0) {
511
      _SEGGER_RTT.aDown[BufferIndex].sName        = sName;
512
      _SEGGER_RTT.aDown[BufferIndex].pBuffer      = pBuffer;
513
      _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize;
514
      _SEGGER_RTT.aDown[BufferIndex].RdOff        = 0;
515
      _SEGGER_RTT.aDown[BufferIndex].WrOff        = 0;
516
    }
517
    _SEGGER_RTT.aDown[BufferIndex].Flags          = Flags;
518
    SEGGER_RTT_UNLOCK();
519
    return 0;
520
  }
521
  return -1;
522
}
523

    
524
/*********************************************************************
525
*
526
*       SEGGER_RTT_Init
527
*
528
*  Function description
529
*    Initializes the RTT Control Block.
530
*    Should be used in RAM targets, at start of the application.
531
*
532
*/
533
void SEGGER_RTT_Init (void) {
534
  _Init();
535
}
536

    
537
/*********************************************************************
538
*
539
*       SEGGER_RTT_SetTerminal
540
*
541
*  Function description
542
*    Sets the terminal to be used for output on channel 0.
543
*
544
*/
545
void SEGGER_RTT_SetTerminal (char TerminalId) {
546
  char ac[2];
547

    
548
  ac[0] = 0xFF;
549
  if (TerminalId < 10) {
550
    ac[1] = '0' + TerminalId;
551
  } else if (TerminalId < 16) {
552
    ac[1] = 'A' + (TerminalId - 0x0A);
553
  } else {
554
    return; // RTT only supports up to 16 virtual terminals.
555
  }
556
  _ActiveTerminal = TerminalId;
557
  SEGGER_RTT_Write(0, ac, 2);
558
}
559

    
560
/*********************************************************************
561
*
562
*       SEGGER_RTT_TerminalOut
563
*
564
*  Function description
565
*    Writes a string to the given terminal
566
*     without changing the terminal for channel 0.
567
*
568
*/
569
int SEGGER_RTT_TerminalOut (char TerminalId, const char* s) {
570
  char ac[2];
571
  int  r;
572

    
573
  ac[0] = 0xFF;
574
  if (TerminalId < 10) {
575
    ac[1] = '0' + TerminalId;
576
  } else if (TerminalId < 16) {
577
    ac[1] = 'A' + (TerminalId - 0x0A);
578
  } else {
579
    return -1; // RTT only supports up to 16 virtual terminals.
580
  }
581
  SEGGER_RTT_Write(0, ac, 2);
582
  r = SEGGER_RTT_WriteString(0, s);
583
  if (TerminalId < 10) {
584
    ac[1] = '0' + _ActiveTerminal;
585
  } else if (TerminalId < 16) {
586
    ac[1] = 'A' + (_ActiveTerminal - 0x0A);
587
  }
588
  SEGGER_RTT_Write(0, ac, 2);
589
  return r;
590
}
591

    
592
/*************************** End of file ****************************/