echo.c File Reference

TCP echo server on port 5031. More...

#include <BoardSupport/inc/stdtypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <inttypes.h>
#include <time.h>
#include <string.h>
#include <Libs/NETlib/net.h>
#include <BoardSupport/inc/BoardSpecific.h>
#include <Common/Common.h>
#include <Common/uartio.h>
#include <Common/timer.h>
#include <Common/CPrintf.h>
#include <BoardSupport/config/netconfig.c>
#include <Common/nbuffer.h>

Macros

#define USE_STATIC_MEMORY   TRUE
 
#define MAX_NBUFFER_SIZE   (1500)
 
#define MAX_TCP_BUFFERS   4
 

Functions

int32_t tcp_echo_cb (SOCKET *so, void *data, uint32_t len, uint32_t ec)
 
void process_data (SOCKET *so)
 
int main (void)
 

Variables

char * program_name = "Echo"
 
far char * domain_name
 
NBuffer_t tcp_buffer [MAX_TCP_BUFFERS]
 
SOCKET * tcp_echo_so = INVALID_SOCKET
 
NBCtl_t bcontrol
 

Detailed Description

                          _         _             _
                       __| |    ___(_) ____ _ __ | |_
                      / _` |   / __| |/ _` | '_ \| __|
                     | (_| | _ \__ \ | (_| | | | | |_
                      \__,_|(_) ___/_|\__, |_| |_|\__|
                     Signalprocessing |___/ Technology
Author
D.SignT GmbH & Co. KG, Claus Hermbusche
Date
2019-06-03

This program works as a TCP echo server with quad buffering (default). A define MAX_TCP_BUFFERS controls the number of buffers. Uncomment define USE_STATIC_MEMORY to use static instead of dynamic memory for buffering. To achieve a better TCP performance, MAX_TCP_BUFFER_SIZE can be increased by multiple of TCP_MAX_PACKET_SIZE. Also linking the tcp_buffer to internal memory (if available) may increase the performance significantly.

To verify this program, first 'ping' the DSP:

>ping 192.168.168.200

or

>ping mydemo

If the settings and network connections are correct, the pings will be replied.

The TCP Echo server will re-send (echo) anything it receives. To verify this, start NetCat (nc) with the following command

>nc 192.168.168.200 5031
           |         |
           |         +-- port 5031 = User Echo Port
           +------------ the DSP's IP address

or

>nc mydemo 5031
      |     |
      |     +------ port 5031 = User Echo Port
      +------------ the DSP hostname

Any characters you type in the console window will be returned. NetCat doesn't send the characters immediately, it will send the entire string following a terminating CR. Please note that the maximum length of the character string is limited by the size of the buffer used for TCP echo (MAX_TCP_BUFFER_SIZE).

Macro Definition Documentation

#define USE_STATIC_MEMORY   TRUE
Examples:
Echo.c, and NetTest.c.
#define MAX_NBUFFER_SIZE   (1500)
#define MAX_TCP_BUFFERS   4
Examples:
Echo.c.

Function Documentation

int32_t tcp_echo_cb ( SOCKET *  so,
void *  data,
uint32_t  len,
uint32_t  ec 
)
253 {
254  /***************************************************************************
255  locals
256  ***************************************************************************/
257  NBCtl_t *bctl = (NBCtl_t *)so-> user_pointer; /* get buffer control */
258  int32_t data_length; // net_recv_event_handler() return parameter
259 
260  /***************************************************************************
261  suppress unused parameter warning
262  ***************************************************************************/
263  UNREFERENCED_PARAMETER(data); // replaced by bctl-> Buf[].Data
264  UNREFERENCED_PARAMETER(ec); // handled in net_recv_event_handler()
265  UNREFERENCED_PARAMETER(len); // len is ignored, data_len is used instead
266 
267 
268  /***************************************************************************
269  Check events
270  If NULL is passed as pLog parameter, no message is printed to output.
271  Use net_recv_event_handler() to determine the data length waiting in the
272  receive buffer
273  ***************************************************************************/
274  data_length = net_recv_event_handler (so, CPrintf); /* with messages */
275  // data_length = net_recv_event_handler (so, NULL); /* without messages */
276 
277  /***************************************************************************
278  net_recv_event_handler() returns the amount of data waiting in the buffer
279  ***************************************************************************/
280  if (data_length)
281  {
282  // CPrintf ("received %"PRId32" bytes\r\n", data_length);
283 
284  if ( bctl == NULL )
285  {
286  /*******************************************************************
287  no control structure available, buffer processing not possible
288  *******************************************************************/
289  return (SOCKET_CB_OK);
290  } // if
291 
292  /***********************************************************************
293  new data is available in buffer that has been previously assigned by
294  socket_define_callback() or set_recv_buffer() function.
295  The receive index bctl-> ri should always point to the active buffer
296  and is maintained in NBufferAcquireBuffer()
297  ***********************************************************************/
298  /***********************************************************************
299  save packet size, useful for later processing
300  ***********************************************************************/
301  bctl-> Buf[bctl-> ri].Size = data_length;
302 
303  /***********************************************************************
304  set process index to this buffer, if not already set.
305  this starts the processing task in main.
306  if bctl-> pi is not BUFFER_EMPTY, processing is already in progress
307  ***********************************************************************/
308  if ( bctl-> pi == BUFFER_EMPTY )
309  {
310  bctl-> pi = bctl-> ri;
311  } // if
312  /***********************************************************************
313  malloc space for new data
314  ***********************************************************************/
315  if ( NBufferAcquireBuffer (so) == NULL)
316  {
317  /*******************************************************************
318  allocation failed due to all buffers in use.
319  this may happen when the receive task works faster than the signal
320  processing task. Send a zero window packet to the remote side to
321  stop the TCP and set OutOfBuffer flag to handle this condition
322  later
323  *******************************************************************/
324  bctl-> OutOfBuffer = TRUE;
325  tcp_send_zero_window ( so );
326  } // if
327  }
328 
329  /***************************************************************************
330  Return true, if socket was not closed before
331  ***************************************************************************/
332  return (SOCKET_CB_OK);
333 }
#define NULL
Definition: net.h:126
Network Buffer Control Structure.
Definition: nbuffer.h:108
int CPrintf(const char *_format,...)
Custom printf function.
Definition: cprintf.c:708
void tcp_send_zero_window(void *so)
send a zero window packet
char * NBufferAcquireBuffer(SOCKET *so)
acquire new buffer
Definition: nbuffer.c:256
int int32_t
Definition: stdint.h:46
#define BUFFER_EMPTY
Definition: nbuffer.h:72
#define UNREFERENCED_PARAMETER(P)
Definition: Common.h:115
#define SOCKET_CB_OK
Definition: net.h:576
void process_data ( SOCKET *  so)
349 {
350  /***************************************************************************
351  locals
352  ***************************************************************************/
353  NBCtl_t *bctl = (NBCtl_t *)so-> user_pointer; /* get buffer control */
354  char *buffer;
355  uint32_t size;
356 
357  if ( bctl == NULL )
358  {
359  /***********************************************************************
360  no control structure available
361  ***********************************************************************/
362  return;
363  } // if
364 
365  /***************************************************************************
366  if allocation failed due to all buffers in use, OutOfBuffer flag was
367  set in tcp_echo_cb(). try to allocate new buffer and send window update on
368  success
369  ***************************************************************************/
370  if ( bctl-> OutOfBuffer )
371  {
372  if ( NBufferAcquireBuffer (so) != NULL )
373  {
374  /*******************************************************************
375  allocation successful,
376  reset OutOfBuffer flag,
377  send window update to start the TCP
378  *******************************************************************/
379  bctl-> OutOfBuffer = FALSE;
380  tcp_send_window_update ( so );
381  } // if
382  } // if
383 
384  /***************************************************************************
385  check received TCP messages
386  process index bctl-> pi is set by the first received packet in tcp_echo_cb()
387  and signals data waiting for processing
388  ***************************************************************************/
389  if ( bctl-> pi != BUFFER_EMPTY )
390  {
391  /***********************************************************************
392  process buffer if necessary
393  the next data is bctl-> Buf[bctl-> pi].Data
394  ***********************************************************************/
395  buffer = (char*)bctl-> Buf[bctl-> pi].Data;
396  size = (uint32_t)bctl-> Buf[bctl-> pi].Size;
397 
398  /***********************************************************************
399  send data back (TCP echo), wait for completion
400  ***********************************************************************/
401  net_send_safe (so, buffer , size, TCP_WAIT);
402 
403  /***********************************************************************
404  since wait flag was set in net_send_safe() call before, it's safe
405  to free this buffer here
406  ***********************************************************************/
407  if ( NBufferFreeBuffer (so) )
408  {
409  /*******************************************************************
410  error occurred, no buffer control structure available
411  assign buffer control structure to socket-> user_pointer
412  during initialization
413  *******************************************************************/
414  prg_exit ("out of memory error");
415  } // if
416  }
417 }
#define prg_exit(s)
Definition: Common.h:267
if(RecentEpoch.tv_usec >=1000000)
Definition: timer.c:124
#define NULL
Definition: net.h:126
Network Buffer Control Structure.
Definition: nbuffer.h:108
char * NBufferAcquireBuffer(SOCKET *so)
acquire new buffer
Definition: nbuffer.c:256
unsigned int uint32_t
Definition: stdint.h:47
static char buffer[100]
Definition: blocksend.c:158
int NBufferFreeBuffer(SOCKET *so)
free packet buffer
Definition: nbuffer.c:364
#define BUFFER_EMPTY
Definition: nbuffer.h:72
void tcp_send_window_update(void *so)
update window size
int main ( void  )
428 {
429  /***************************************************************************
430  locals
431  ***************************************************************************/
432  int main_loop = 1; /* main loop switch, set to 0 to exit */
433  timeval stamp1, stamp2, delta; /* used to determine startup time */
434  char conversion_buffer[16];
435 
436  /***************************************************************************
437  initialize application (e.g. timer clocks, PLL settings, EMIF etc.)
438  (ref. \Common\Common.c)
439  ***************************************************************************/
440  AppInit (GET_CLOCK);
441 
442  /***************************************************************************
443  select output device for CPrintf (ref. \Common\cprintf.c)
444  possible settings:
445  CPRINTF_UART_OUTPUT -> output to UART
446  CPRINTF_CCS_OUTPUT -> output to CCS
447  CPRINTF_UART_OUTPUT | CPRINTF_CCS_OUTPUT -> output to UART and CCS
448  ***************************************************************************/
449  CPrintf_select_output (CPRINTF_DEFAULT_OUTPUT); /* default outputs */
450 
451  /***************************************************************************
452  print a start up message
453  ***************************************************************************/
454  START_UP_MESSAGE (BLANK_REV NETLIB_REV);
455 
456  /**************************************************************************/
457  // CPrintfProgress (" Heap check ");
458  // at least 0x2000 bytes required for this app
459  /**************************************************************************/
460  ASSERT_HEAP (initial_heap_size, 0x2000);
461  // CPrintfProgressSuccess();
462 
463  /**************************************************************************/
464  CPrintfProgress (" Setup system time ");
465  // 1 milli seconds resolution
466  /**************************************************************************/
469  CPrintf (" *** timer %d mapped to CPU int %d ***\r\n",
471 
472  /**************************************************************************/
473  CPrintfProgress (" Enable interrupts ");
474  /**************************************************************************/
477 
478  /**************************************************************************/
479  CPrintfProgress (" Start system timer ");
480  /**************************************************************************/
481  StartSystemTimer ();
483  CPrintf (" *** timer %d running at %"PRId32" Hz ***\r\n", SystemTimerDev, RES_SECONDS/GetSystemTimerRes());
484 
485  /***************************************************************************
486  measure network initialization time
487  ***************************************************************************/
488  stamp1 = GetTimeStamp();
489 
490  /**************************************************************************/
491  CPrintfProgress (" Initialize network ");
492  /**************************************************************************/
493  InitializeNetwork ( 64); // 64 bytes for ping
494 
495  /**************************************************************************
496  open sockets
497  **************************************************************************/
499  ANY_PORT,
500  5031,
502  TCP_INIT_FUNC);
503  if ( tcp_echo_so == INVALID_SOCKET )
504  {
505  prg_exit ("socket_open() error"); /* possibly insufficient heap */
506  } // if
507 
508  /***************************************************************************
509  attach buffer control structure to socket
510  (required for NBufferAcquireBuffer() later)
511  ***************************************************************************/
512  tcp_echo_so-> user_pointer = (void *)&bcontrol;
513 
514  /***************************************************************************
515  initially malloc space for data
516  NBufferAcquireBuffer() allocates new buffer space and modifies the
517  bcontrol structure data buffer pointer and receive index
518  ***************************************************************************/
520  {
521  prg_exit ("out of memory error");
522  } // if
523 
524  /***************************************************************************
525  install callback function
526  NBufferAcquireBuffer() has modified receive index ri to point to the next
527  buffer
528  ***************************************************************************/
530 
531  /***************************************************************************
532  set keep alive time 10 seconds (three unanswered packets within 10 seconds)
533  ***************************************************************************/
535 
537 
538  stamp2 = GetTimeStamp();
539 
540  tv_interval (&delta, &stamp1, &stamp2);
541  CPuts (" network startup time [sec]: ");
543  "%"PRId32".%03"PRId32"\r\n"
545  delta.tv_sec,
546  delta.tv_usec/1000);
547 
548  /***************************************************************************
549  main program loop: set main_loop to 0 to exit loop
550  ***************************************************************************/
551  CPuts ("\r\n Entering main loop ...\r\n");
552  while ( main_loop )
553  {
554  /***********************************************************************
555  process net_isq()
556  ***********************************************************************/
557  net_isq (); // process ISQ
558 
559  /***********************************************************************
560  monitor link status
561  ***********************************************************************/
563 
564  /***********************************************************************
565  try to detect IP assignment
566  if DHCP is used, the assigned IP address may change
567  ***********************************************************************/
569  {
570  /*******************************************************************
571  print what to do next
572  *******************************************************************/
573  CPrintf (" Establish a TCP connection on port %d:\r\n", tcp_echo_so-> src_port);
574 
575  if (domain_name) CPrintf (">nc %s.%s %d\r\n or\r\n",
576  eth.ip,
577  domain_name,
578  tcp_echo_so-> src_port);
579  CPrintf (">nc %s %d\r\n",
580  inet_ntoa(get_ip_address(0), conversion_buffer),
581  tcp_echo_so-> src_port);
582 
583  CPuts (" Any characters you type into the nc console will be echoed back\r\n when you press enter until the connection is closed.\r\n");
584  }
585 
586  /***********************************************************************
587  process data
588  ***********************************************************************/
590 
591  /***********************************************************************
592  show that the program is running, perform symbol animation
593  ***********************************************************************/
595  }
596 
597  /***************************************************************************
598  exit program, shut down peripherals
599  ***************************************************************************/
600  return (0);
601 }
#define prg_exit(s)
Definition: Common.h:267
void BoardEnableInterrupts(void)
global enable interrupts
Definition: BoardSpecific.c:365
NBuffer_t * Buf
Definition: nbuffer.h:113
void socket_define_callback(SOCKET *so, int32_t(*call_back_function)(SOCKET *, void *, uint32_t, uint32_t), void *data, uint16_t maxdata)
Install a user callback function for a specific socket.
#define ANIMATE_SYMBOLS_COUNT
Definition: BoardSpecific.h:268
int16_t tcp_set_keep_alive_time(SOCKET *so, uint32_t time)
Set keep alive time.
void StartSystemTimer(void)
start system timer
Definition: timer.c:447
#define RES_MSECONDS
Definition: timer.h:67
char * inet_ntoa(uint32_t i_addr, char *s)
Convert IP-address from 0xbbaaddcc to "aaa.bbb.ccc.ddd".
uint16_t CPrintf_select_output(uint16_t device)
Definition: cprintf.c:206
#define ASSERT_HEAP(i, h)
Definition: Common.h:262
#define ANY_PORT
Definition: net.h:519
#define NULL
Definition: net.h:126
time_t GetSystemTimerRes(void)
Definition: timer.c:160
#define KA_TIMEOUT(x)
Definition: BoardSpecific.h:230
#define GET_CLOCK
Definition: BoardSpecific.h:258
int CPrintf(const char *_format,...)
Custom printf function.
Definition: cprintf.c:708
#define VT100_DEFAULT
Definition: cprintf.h:150
void SetupSystemTime(int32_t cpuint, int port, time_t resolution)
Setup System Time.
Definition: timer.c:392
void AppInit(uint32_t dsp_clock)
Initialize application.
Definition: Common.c:230
SOCKET * tcp_echo_so
Definition: echo.c:200
char * Data
Definition: nbuffer.h:92
uint32_t initial_heap_size
Definition: Common.c:140
#define TCP_INIT_FUNC
Definition: net.h:499
#define CPRINTF_DEFAULT_OUTPUT
Definition: BoardSpecific.h:129
#define MAX_NBUFFER_SIZE
Definition: echo.c:139
#define VT100_RED
Definition: cprintf.h:143
char * NBufferAcquireBuffer(SOCKET *so)
acquire new buffer
Definition: nbuffer.c:256
uint16_t CPrintAnimatedSymbol(char *c, time_t period, size_t size)
Definition: cprintf.c:816
int InitializeNetwork(uint16_t icmp_size)
Initialize MAC, sockets and protocols.
Definition: BoardSpecific.c:597
char sym_animate[]
Definition: BoardSpecific.c:129
far char * domain_name
SOCKET * socket_open(char *dest_addr, uint16_t dest_port, uint16_t src_port, uint8_t data_type, int32_t(*init_func)(SOCKET *))
Create a new socket.
int32_t tcp_echo_cb(SOCKET *so, void *data, uint32_t len, uint32_t ec)
Definition: echo.c:252
Definition: timer.h:75
#define GetTimeStamp()
Definition: timer.h:81
void tv_interval(timeval *e, timeval *t1, timeval *t2)
compute elapsed time
Definition: timer.c:336
NBCtl_t bcontrol
Definition: echo.c:206
#define ANY_ADDRESS
Definition: net.h:511
#define SYSTEM_TIMER_INT
Definition: BoardSpecific.h:174
#define SYSTEM_TIMER
Definition: BoardSpecific.h:167
uint32_t get_ip_address(uint16_t dev_nr)
Get configured IP address.
#define DATATYPE_CHAR
Definition: net.h:489
void net_isq(void)
The main polling function for processing sockets, must be periodically called in the main application...
char ip[31]
Definition: net.h:170
#define BLANK_REV
Definition: BoardSpecific.h:191
void process_data(SOCKET *so)
Definition: echo.c:348
Uint16 SystemTimerDev
adapter_t eth
Definition: netconfig.c:62
#define INVALID_SOCKET
Definition: net.h:540
uint16_t monitor_ip_address(tpOutputFunc pLog)
monitor IP assignment
Definition: BoardSpecific.c:545
#define START_UP_MESSAGE(rev)
Definition: BoardSpecific.h:192
#define RES_SECONDS
Definition: timer.h:70
uint16_t monitor_link_status(tpOutputFunc pLog)
monitor link status change
Definition: BoardSpecific.c:497
int CPuts(const char *_ptr)
Definition: cprintf.c:399
time_t tv_sec
Definition: timer.h:77
#define CPrintfProgress(s)
Definition: cprintf.h:230
time_t tv_usec
Definition: timer.h:78
int16_t ri
Definition: nbuffer.h:133
#define CPrintfProgressSuccess()
Definition: cprintf.h:263

Variable Documentation

char* program_name = "Echo"
far char* domain_name
Examples:
Echo.c.
SOCKET* tcp_echo_so = INVALID_SOCKET
Examples:
Echo.c.
NBCtl_t bcontrol
Initial value:
=
{
sizeof(NBuffer_t),
0,
0,
0,
}
Network Buffer.
Definition: nbuffer.h:84
#define MAX_NBUFFER_SIZE
Definition: echo.c:139
#define MAX_TCP_BUFFERS
Definition: echo.c:173
NBuffer_t tcp_buffer[MAX_TCP_BUFFERS]
Definition: echo.c:195
#define BUFFER_EMPTY
Definition: nbuffer.h:72