]> rtime.felk.cvut.cz Git - pes-rpp/rpp-test-sw.git/blob - rpp-test-sw/commands/cmd_nc.c
Apply uncrustify
[pes-rpp/rpp-test-sw.git] / rpp-test-sw / commands / cmd_nc.c
1 /*
2  * Copyright (C) 2012-2013 Czech Technical University in Prague
3  *
4  * Created on: Aug 9, 2013
5  *
6  * Authors:
7  *     - Jan Doležal
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * File : cmd_lwip.c
23  *
24  * Abstract:
25  *      This file contains commands for LwIP test
26  *
27  */
28
29 #include "cmd_nc.h"
30
31 #ifndef DOCGEN
32
33 #include <string.h>
34 #include <ctype.h>
35
36 #include "rpp/rpp.h"
37 #include "lwip/udp.h"
38 #if !NO_SYS
39 #include "lwip/api.h" //netconn
40 #else
41 #include "lwip/timers.h" //for updating timers, when NO_SYS == 1
42 #include "lwip/tcp.h"
43 #include "lwip/tcp_impl.h"
44 #endif
45
46 #define INTERFACE_INSTANCE_NUMBER 0
47
48 #define BUF_SIZE 80
49 /* only for use in interactive mode (not thread) */
50 char in_buffer[BUF_SIZE];
51 uint8_t buff_index = 0;
52
53 /* when -p option not given, srcPort is used; when nc run repeatedly,
54  * even though netconn was removed, netconn_new() with previously used port
55  * might still cause errors like address in use, therefore in srcPort
56  * there next port NO prepared to be used */
57 uint16_t srcPort = 1025; /* initial value */
58
59 #if !NO_SYS
60 uint8_t tasks_running = 0, taskNameNum = 0;
61 boolean_t closeths; /* variable controling threads closing */
62
63 /* argument storing parameters from command line, if started as thread, they are coppied to stack of thread and cmd_do_init_nc() is acknowledged by semaphore */
64 struct nc_arg {
65         uint16_t portNO, srcPortNO;
66         ip_addr_t remoteIP;
67         xSemaphoreHandle args_coppied;
68         boolean_t thread; /* variable controling whether this instance should run as thread */
69         boolean_t udp, listen, netLoop, test, srcPortSpec;
70         err_t err;
71 };
72
73
74 /* nc task */
75 void run_nc(void *arg)
76 {
77         err_t err = ERR_OK;
78         uint8_t input = 0;
79         uint8_t tries;
80         uint32_t index;
81         uint8_t *payload;
82         struct netconn *netconn, *newconn;
83
84         newconn = NULL;
85         struct netbuf *remoteData = NULL, *localData = NULL;
86         struct pbuf *p;
87         boolean_t ncStop = FALSE;
88         boolean_t flush = FALSE;
89         struct nc_arg *nc_arg = (struct nc_arg*)arg;
90         struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
91
92         /* fill options from argument */
93         uint16_t portNO = nc_arg->portNO, srcPortNO = nc_arg->srcPortNO;
94         ip_addr_t remoteIP = nc_arg->remoteIP;
95         boolean_t udp = nc_arg->udp, listen = nc_arg->listen, srcPortSpec = nc_arg->srcPortSpec, netLoop = nc_arg->netLoop, test = nc_arg->test;
96         boolean_t thread = nc_arg->thread; /* variable controling whether this instance should run as thread */
97 #if DEBUG
98         uint8_t thread_inst = (taskNameNum-1); /* store number of this thread */
99 #endif
100         tasks_running++;
101
102
103         /* switch off closing of tasks/threads */
104         closeths = FALSE;
105
106
107         /*** make connection ***/
108         while (!closeths) { /* shouldn't get here twice, used only for break which leads us down to unalocating of sources */
109                 /* let nc initiator go */
110                 if (thread && /* just in case --> */ nc_arg->args_coppied != NULL && xSemaphoreGive(nc_arg->args_coppied) != pdTRUE) break;
111                 /* fill netconn struct */
112                 netconn = netconn_new(udp ? NETCONN_UDP : NETCONN_TCP);
113                 if (netconn == NULL) {
114                         err = ERR_NETCONN_NEW;
115                         break;
116                 }
117
118                 tries = 15; /* how many local ports to try */
119                 /* bind filled netconn with local interface address and source port number */
120                 while ( tries-- && (err = netconn_bind(netconn, &(netif->ip_addr), srcPortNO) ) == ERR_USE && !closeths) {
121                         if (srcPortSpec) break;  /* if port was explicitly specified (we shouldn't change user's port number just like that ;) ) */
122                         srcPort++;
123                         srcPortNO = srcPort;
124                 }
125                 if (err != ERR_OK || !tries) {
126                         newconn = netconn; /* deleting newconn is done anyway, so delete netconn this way */
127                         err = ERR_BINDING;
128                         break;
129                 }
130
131                 /* adjust recvtimeout time and tries to different values, if user shouldn't loose control over cmd processor at any time */
132                 netconn_set_recvtimeout(netconn, CONNECTING_TIMEO);
133                 tries = CONNECTING_TRIES;
134
135                 if (listen) { /* -l <PORT> option */
136                         if (!udp) { /* TCP - make connection */
137                                 /* make listening netconn */
138                                 netconn_listen(netconn);
139                                 /* accept connection to newconn */
140                                 while ( tries-- && (err = netconn_accept(netconn, &newconn)) == ERR_TIMEOUT && (thread || rpp_sci_read_nb(1, &input) != SUCCESS)) ;
141                                 if (err != ERR_OK) {
142                                         newconn = netconn;
143                                         err = ERR_CONN_ACCEPT;
144                                         break;
145                                 }
146                                 else
147                                         netconn_delete(netconn);  /* we don't need listening netconn anymore */
148                         }
149                         else
150                         {
151                                 while (tries-- && !closeths) {
152                                         /* allow user to interrupt waiting for "udp connection" - in case this is not thread */
153                                         if (!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)) {
154                                                 newconn = netconn; /* deleting newconn is done anyway, so delete netconn this way */
155                                                 err = ERR_CONNECTING;
156                                                 break;
157                                         }
158
159                                         if ((err = netconn_recv(netconn, &remoteData)) == ERR_OK) { /* wait for data, from which we will determine our peer address and portNO */
160                                                 remoteIP = remoteData->addr;
161                                                 portNO = remoteData->port;
162                                                 if (test) netbuf_delete(remoteData);
163                                                 break;
164                                         }
165                                         else
166                                         {
167                                                 if (err == ERR_TIMEOUT) continue;
168                                                 else
169                                                 {
170                                                         newconn = netconn;
171                                                         break;
172                                                 }
173                                         }
174                                 }
175                                 if (!tries) {
176                                         newconn = netconn;
177                                         err = ERR_CONNECTING;
178                                         break;
179                                 }
180                         }
181                 }
182
183                 if (!listen || (listen && udp) ) { /* connect to remote node */
184                         newconn = netconn;
185                         netconn = NULL;
186                         if ( ( err = netconn_connect(newconn, &remoteIP, portNO) ) != ERR_OK )
187                                 break;
188                 }
189
190                 /* we will block for time specified on next line on netconn to receive data, if it does not come, we block for user sci input */
191                 netconn_set_recvtimeout(newconn, 50);
192
193                 if (udp && (localData = netbuf_new()) == NULL) {
194                         err = ERR_MEM;
195                         break;
196                 }
197
198                 if (test) { /* -d option; sends packets to the opposite node and doesn't receive anything */
199                         index = 0;
200                         char strbuf[13];
201                         int strlen;
202                         //netconn_set_recvtimeout(newconn, 1);
203                         while (!closeths && index++ < 4294967295) {
204                                 /* destroy all incomming data to prevent pbufs from running out */
205                                 /*while(remoteData != NULL ||  (err = netconn_recv ( newconn, &remoteData )) != ERR_TIMEOUT){
206                                     netbuf_delete(remoteData);
207                                     remoteData = NULL;
208                                    }*/
209                                 /* allow user to interrupt sending */
210                                 if (!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)) break;
211                                 strlen = sprintf(strbuf,"%d\r\n",index);
212                                 if (!udp) {
213                                         if ((err = netconn_write(newconn, strbuf, strlen, NETCONN_COPY)) != ERR_OK) break;
214                                 }
215                                 else
216                                 {
217                                         payload = netbuf_alloc(localData,strlen);
218                                         if (payload != NULL) {
219                                                 netbuf_take(localData,strbuf,strlen);
220                                                 netbuf_len(localData) = strlen;
221                                                 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
222                                         }
223                                         else
224                                         {
225                                                 err = ERR_MEM;
226                                                 break;
227                                         }
228                                 }
229                         }
230                         break;
231                 }
232
233                 if (netLoop) { /* -m option */
234                         err = ERR_OK;
235                         /* send some data to opposite node so it knows its peer (this node) ; ATENTION if opposite node was not running in time this is send, then it wont get known this node's connection info */
236                         if (udp && !listen) {
237                                 payload = netbuf_alloc(localData,1);
238                                 if (payload != NULL) {
239                                         input = 0;
240                                         netbuf_take(localData,&input,1);
241                                         netbuf_len(localData) = 1;
242                                         if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
243                                 }
244                                 else
245                                 {
246                                         err = ERR_MEM;
247                                         break;
248                                 }
249                         }
250                         while (!closeths) {
251                                 if (!thread && (rpp_sci_read_nb(1, &input) == SUCCESS)) break;  /* allow user to interrupt operation */
252                                 if ( remoteData != NULL ||  (err = netconn_recv( newconn, &remoteData )) != ERR_TIMEOUT ) {
253                                         if (err == ERR_OK) {
254                                                 p = remoteData->p;
255                                                 /**/
256                                                 while (p->ref > 1) /* if (p->ref > 1) p->ref = 1; */
257                                                         pbuf_free(p);
258                                                 /**/
259                                                 while (p != NULL) {
260                                                         if (!udp)
261                                                                 netconn_write(newconn, p->payload, p->len, NETCONN_COPY);  /*NETCONN_DONTBLOCK*/
262                                                         else
263                                                         {
264                                                                 payload = netbuf_alloc(localData,p->len);
265                                                                 if (payload != NULL) {
266                                                                         netbuf_take(localData,p->payload,p->len);
267                                                                         netbuf_len(localData) = p->len;
268                                                                         if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
269                                                                 }
270                                                                 else
271                                                                 {
272                                                                         err = ERR_MEM;
273                                                                         break;
274                                                                 }
275                                                         }
276                                                         p = p->next;
277                                                 }
278                                                 netbuf_delete(remoteData);
279                                                 remoteData = NULL;
280                                         }
281                                         else
282                                                 break;
283                                 }
284                         }
285                         if (err == ERR_TIMEOUT) err = ERR_OK;  /* timeout is not error here, this occurs on interrupt of while cycle */
286                         break;
287                 }
288
289                 /* only active user can control this section XXX: maybe should move to init startup condition handler */
290                 if (thread) break;
291
292                 /* INTERACTIVE PART */
293
294                 /* receive remote data and print them to sci, receive sci data and write them to netconn */
295                 while (!ncStop) {
296                         if (rpp_sci_read_nb(1, &input) != SUCCESS) {
297                                 if ( remoteData != NULL || (err = netconn_recv( newconn, &remoteData )) != ERR_TIMEOUT) {
298                                         if (err == ERR_OK) {
299                                                 /* print remote data to SCI */
300                                                 p = remoteData->p;
301                                                 while (p != NULL) {
302                                                         index = 0;
303                                                         payload = p->payload;
304                                                         while (index < p->len) {
305                                                                 rpp_sci_printf("%c",payload[index]);
306                                                                 index++;
307                                                         }
308                                                         p = p->next;
309                                                 }
310                                                 netbuf_delete(remoteData);
311                                                 remoteData = NULL;
312                                         }
313                                         else
314                                                 break;  /* receive error - e.g. newconn was closed */
315                                 }
316                                 if (err == ERR_TIMEOUT) err = ERR_OK;
317                                 continue;
318                         }
319
320                         // Backspace and Delete
321                         if (input == 8 || input == 127) {
322                                 if (buff_index > 0) {
323                                         buff_index--;
324                                         rpp_sci_putc('\b');
325                                         rpp_sci_putc(' ' );
326                                         rpp_sci_putc('\b');
327                                 }
328
329                                 // Line feed or Carriage return
330                         }
331                         else if (input == 10 || input == 13) {
332                                 in_buffer[buff_index] = 13;
333                                 buff_index++;
334                                 in_buffer[buff_index] = 10;
335                                 buff_index++;
336                                 flush = TRUE;
337                                 rpp_sci_putc('\r');
338                                 rpp_sci_putc('\n');
339
340                                 // If is any printable character
341                         }
342                         else if (isprint(input) || input == 9) {
343
344                                 // Store character and increment buffer index
345                                 in_buffer[buff_index] = input;
346                                 buff_index++;
347                                 rpp_sci_putc(input);
348
349                                 // Check if buffer is full and force flush
350                                 if (buff_index == BUF_SIZE - 3)
351                                         flush = TRUE;
352                                 // All other character stops nc
353                         }
354                         else {
355                                 ncStop = TRUE;
356                                 flush = TRUE;
357                         }
358
359                         if (flush) {
360                                 if (!udp)
361                                         netconn_write(newconn, in_buffer, buff_index, NETCONN_COPY);
362                                 else
363                                 {
364                                         payload = netbuf_alloc(localData,buff_index);
365                                         if (payload != NULL) {
366                                                 netbuf_take(localData,in_buffer,buff_index);
367                                                 netbuf_len(localData) = buff_index;
368                                                 if ((err = netconn_send(newconn, localData)) != ERR_OK) break;
369                                         }
370                                         else
371                                         {
372                                                 err = ERR_MEM;
373                                                 break;
374                                         }
375                                 }
376                                 // Reset variables
377                                 buff_index = 0;
378                                 flush = FALSE;
379                         }
380                 }
381                 break;
382         }
383 #ifdef DEBUG
384         if (thread) rpp_sci_printf("NC: THREAD NO.%d FINISHED\r\n", thread_inst);
385 #endif
386         if (udp && localData != NULL) netbuf_delete(localData);
387         if (remoteData != NULL) netbuf_delete(remoteData);
388         if (newconn != NULL && !udp) netconn_close(newconn);
389         netconn_delete(newconn);
390         tasks_running--;
391         if (!thread)
392                 nc_arg->err = err;  /* only user controlled task is in front */
393         if (thread) vTaskDelete(NULL);
394 }
395 #else /* if !NO_SYS */
396 boolean_t connected;
397 boolean_t sent;
398 boolean_t ncStop;
399
400 err_t nc_recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
401 {
402         uint16_t index;
403         uint8_t *payload;
404
405         if (err == ERR_ABRT) {
406                 rpp_sci_printk("recv abrt\n");
407                 return ERR_ABRT;
408         }
409         /* print remote data to SCI */
410         while (p != NULL) {
411                 index = 0;
412                 payload = p->payload;
413                 while (index < p->len) {
414                         rpp_sci_printk("%c",payload[index]);
415                         index++;
416                 }
417                 p = p->next;
418         }
419         return ERR_OK;
420 }
421
422 void nc_udp_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
423 {
424         uint16_t index;
425         uint8_t *payload;
426
427         /* print remote data to SCI */
428         while (p != NULL) {
429                 index = 0;
430                 payload = p->payload;
431                 while (index < p->len) {
432                         rpp_sci_printk("%c",payload[index]);
433                         index++;
434                 }
435                 p = p->next;
436         }
437         //pbuf_free(p);
438 }
439
440 void nc_udp_listen_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
441 {
442         connected = TRUE;
443         err_t err = udp_connect(pcb, addr, port);
444         LWIP_ASSERT(("nc_init: udp_listen_connect failed"), err == ERR_OK);
445         udp_recv(pcb, nc_udp_recv_callback, NULL);
446         nc_udp_recv_callback(arg, pcb, p, addr, port);
447 }
448
449 void nc_err_callback(void *arg, err_t err)
450 {
451         rpp_sci_printk("err clbck\n");
452         LWIP_DEBUGF(LWIP_DBG_ON, ("nc_err: %s", lwip_strerr(err)));
453
454         ncStop = TRUE;
455 }
456
457 err_t nc_sent_callback(void *arg, struct tcp_pcb *pcb, u16_t len)
458 {
459         sent = TRUE;
460         return ERR_OK;
461 }
462
463 err_t nc_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
464 {
465         struct tcp_pcb * *newone = arg;
466
467         *newone = newpcb; /* pass accepted connection to main app loop */
468
469         connected = TRUE;
470
471         /* Set up the various callback functions */
472         tcp_recv(newpcb, nc_recv_callback);
473         tcp_err(newpcb, nc_err_callback);
474         tcp_sent(newpcb, nc_sent_callback);
475
476         return ERR_OK;
477 }
478
479 err_t nc_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err)
480 {
481
482         /* Set up the various callback functions */
483         tcp_recv(tpcb, nc_recv_callback);
484         tcp_err(tpcb, nc_err_callback);
485         tcp_sent(tpcb, nc_sent_callback);
486
487         connected = TRUE;
488         rpp_sci_printk("connected\n");
489         return ERR_OK;
490 }
491
492 err_t nc_tmirror_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
493 {
494         if (err == ERR_ABRT) {
495                 rpp_sci_printk("recv abrt\n");
496                 return ERR_ABRT;
497         }
498         while (p != NULL) {
499                 if (tcp_write(tpcb, p->payload, p->len, TCP_WRITE_FLAG_COPY) != ERR_OK) {
500                         rpp_sci_printk("error writing to newpcb - tcp_write\n");
501                         return -1;
502                 }
503                 if (tcp_output(tpcb) != ERR_OK) { /* when we want to send data immediately */
504                         rpp_sci_printk("newpcb output err - tcp\n");
505                         return -1;
506                 }
507                 p = p->next;
508         }
509         return ERR_OK;
510 }
511
512 void nc_umirror_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
513 {
514         struct pbuf *pbuf;
515
516         while (p != NULL) {
517                 pbuf = pbuf_alloc(PBUF_TRANSPORT, p->len, PBUF_RAM);
518                 if (pbuf == NULL) {
519                         rpp_sci_printk("error allocating pbuf - udp_send\n");
520                         //p = p->next;
521                         continue;
522                 }
523                 if (pbuf_take(pbuf, p->payload, p->len) != ERR_OK) {
524                         rpp_sci_printk("pbuf mem err (small pbuf) - udp_send\n");
525                         continue;
526                 }
527                 if (udp_send(pcb, pbuf) != ERR_OK) {
528                         rpp_sci_printk("error sending to pcb - udp_send\n");
529                         continue;
530                 }
531                 p = p->next;
532         }
533 }
534
535
536 #endif /* !NO_SYS */
537
538 /*
539  * this function has two operational modes, depending on LwIP settings
540  * NO_SYS == 1 - this is for testing raw API, there is only one task working with IP stack allowed when using this mode
541  * NO_SYS == 0 - this is for testing netconn API, you can let more tasks to work with IP stack
542  */
543 int cmd_do_init_nc(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
544 {
545         if (!isPostInitialized()) {
546                 rpp_sci_printf("Eth not initialized run 'ethinit' command first.\n");
547                 return FAILURE;
548         }
549         err_t err = ERR_OK;
550         uint16_t portNO, srcPortNO = 0;
551         ip_addr_t remoteIP;
552         boolean_t help = FALSE, udp = FALSE, listen = FALSE, netLoop = FALSE, test = FALSE, srcPortSpec = FALSE;
553         uint8_t pindex;
554
555         buff_index = 0;
556         /* initialize arguments and thread name */
557 #if !NO_SYS
558         uint8_t name[5] = "nc";
559         name[4] = '\0';
560         struct nc_arg nc_arg; /* create space for handing args to nc_run() */
561         nc_arg.thread = FALSE;
562 #else
563         uint8_t input = 0;
564         boolean_t flush = FALSE;
565         uint32_t index;
566         struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
567         struct tcp_pcb *tpcb, *tnewpcb;
568         struct udp_pcb *pcb;
569         struct pbuf *p; /* udp send */
570 #endif
571
572         /* examine parameters */
573         for (pindex = 1; param[pindex] != 0; pindex++) {
574                 if        (strncmp((char*)param[pindex], "-h", 3) == 0) {
575                         help = TRUE;
576                         break;
577                 }
578                 else if (strncmp((char*)param[pindex], "-u", 3) == 0) {
579                         udp = TRUE;
580 #if !NO_SYS
581                 }
582                 else if (strncmp((char*)param[pindex], "-t", 3) == 0)
583                         nc_arg.thread = TRUE;
584                 else if (strncmp((char*)param[pindex], "-c", 3) == 0) {
585                         closeths = TRUE;
586                         return ERR_OK;
587 #endif
588                 }
589                 else if (strncmp((char*)param[pindex], "-l", 3) == 0 && !srcPortSpec) {
590                         listen = TRUE;
591                         srcPortNO = rpp_eth_portStrToInt((uint8_t*)param[++pindex]);
592                         if (srcPortNO == 0) {
593                                 rpp_sci_printf("E wrong portNO, portNO must follow immediately after -l option\r\n");
594                                 return BAD_PORT_NO;
595                         }
596                         srcPortSpec = TRUE;
597                 }
598                 else if (strncmp((char*)param[pindex], "-p", 3) == 0 && !srcPortSpec) {
599                         srcPortNO = rpp_eth_portStrToInt((uint8_t*)param[++pindex]);
600                         if (srcPortNO == 0) {
601                                 rpp_sci_printf("E wrong portNO, portNO must follow immediately after -p option\r\n");
602                                 return BAD_PORT_NO;
603                         }
604                         srcPortSpec = TRUE;
605                 }
606                 else if (strncmp((char*)param[pindex], "-m", 3) == 0)
607                         netLoop = TRUE;
608                 else if (strncmp((char*)param[pindex], "-d", 3) == 0)
609                         test = TRUE;
610                 else if ( (err = rpp_eth_stringToIP(&remoteIP, (uint8_t*)param[pindex])) == SUCCESS ) {
611                         portNO = rpp_eth_portStrToInt((uint8_t*)param[++pindex]);
612                         if (portNO == 0) {
613                                 rpp_sci_printf("E wrong portNO, portNO must follow immediately after IP address\r\n");
614                                 return BAD_PORT_NO;
615                         }
616                 }
617                 else {
618                         rpp_sci_printf("ERR: check option name, option combination, IP address format\r\n");
619                         help = TRUE;
620                         err = BAD_OPTION;
621                         break;
622                 }
623         }
624
625         /* TODO: additional testing of parameters mutual exclusion */
626         /* valid combinations:
627            nc <addr> <port> [-p <port>] [-u] [-t]
628            nc -l <port> [-u] [-t]
629            nc <addr> <port> -m [-p <port>] [-u] [-t]
630            nc <addr> <port> -d [-p <port>] [-u] [-t]
631            nc -l <port> -m [-u] [-t]
632            nc -l <port> -d [-u] [-t]
633          */
634
635         /* usage of command */
636         if (help || !param[1]) {
637                 rpp_sci_printf("-u udp, -t thread, -c close tasks, -l listen, -p source port, -m ping/mirror, -d test\r\n\n");
638                 rpp_sci_printf("usage:\tnc -l <port> [-u] [-m [-t] | -d [-t]]\r\n\t\tlistens on port for connection\r\n");
639                 rpp_sci_printf("\tnc <address> <port> [-p <port>] [-u] [-m [-t] | -d [-t]]\r\n\t\tconnects to the address on port NO.\r\n");
640                 rpp_sci_printf("\tnc -c\r\n\t\tdeletes all running threads.\r\n");
641                 rpp_sci_printf("opts:\t-t run as stand alone task\r\n\t-c close all stand alone tasks\r\n");
642                 rpp_sci_printf("\t-l <port> listen on given port for incomming connection\r\n\t-p <port> use as local port when connecting to remote node\r\n\t");
643                 rpp_sci_printf("\t-m send all incomming data back to sender\r\n\t-d sends many testing packets containing packet number in ASCII as data\r\n");
644                 rpp_sci_printf("Note: when using udp -u and listening -l options, first node data was received from is considered as peer for communication.\r\n");
645                 return err;
646         }
647
648         /* determine srcPortNO from predefined value if not done yet (from argument given) */
649         if (!srcPortSpec)
650                 //udp_new_port();
651                 srcPortNO = srcPort++;
652
653 #if !NO_SYS /* netconn api */
654
655         /* prepare args */
656         nc_arg.srcPortNO = srcPortNO;
657         nc_arg.portNO = portNO;
658         nc_arg.remoteIP.addr = remoteIP.addr;
659         nc_arg.udp = udp;
660         nc_arg.listen = listen;
661         nc_arg.netLoop = netLoop;
662         nc_arg.test = test;
663         nc_arg.srcPortSpec = srcPortSpec;
664
665         if (nc_arg.thread) {
666                 /* prepare semaphore */
667                 vSemaphoreCreateBinary(nc_arg.args_coppied);
668                 xSemaphoreTake(nc_arg.args_coppied, 0);
669                 /* add number to task name */
670                 taskNameNum = (taskNameNum%100);
671                 name[2] = (taskNameNum/10) + '0';
672                 name[3] = (taskNameNum%10) + '0';
673                 rpp_sci_printf("STARTING THREAD: %s\r\n", name);
674                 taskNameNum++;
675                 /* start thread */
676                 if ((err = xTaskCreate(&run_nc,(const signed char*)name, ncTaskStackSize, &nc_arg, ncTaskPriority, NULL)) == pdPASS) {
677                         /* block on semaphore, till new thread copies arg to own stack */
678                         xSemaphoreTake( nc_arg.args_coppied, portMAX_DELAY );
679                         vSemaphoreDelete(nc_arg.args_coppied);
680                 }
681                 else {
682                         vSemaphoreDelete(nc_arg.args_coppied);
683                         return err;
684                 }
685         }
686         else
687         {
688                 taskNameNum++;
689                 run_nc(&nc_arg);
690                 return nc_arg.err;
691         }
692 #else /* raw LwIP API */
693         ncStop = FALSE;
694         connected = FALSE;
695         sent = TRUE;
696         if (udp) {
697                 pcb = udp_new();
698                 LWIP_ASSERT(("nc_init: udp_new failed"), pcb != NULL);
699                 if (pcb == NULL) return -1;
700                 err = udp_bind(pcb, &(netif->ip_addr), srcPortNO);
701                 CC_ASSERT(("nc_init: udp_bind failed: %s", lwip_strerr(err)), err == ERR_OK);
702                 if (err != ERR_OK) return -1;
703         }
704         else
705         {
706                 tpcb = tcp_new();
707                 LWIP_ASSERT(("nc_init: tcp_new failed"), tpcb != NULL);
708                 if (tpcb == NULL) return -1;
709                 err = tcp_bind(tpcb, &(netif->ip_addr), srcPortNO);
710                 CC_ASSERT(("nc_init: tcp_bind failed: %s", lwip_strerr(err)), err == ERR_OK);
711                 if (err != ERR_OK) return -1;
712         }
713
714         if (!udp) {
715                 if (listen) {
716                         tpcb = tcp_listen(tpcb);
717                         LWIP_ASSERT(("nc_init: tcp_listen failed"), tpcb != NULL);
718                         /* initialize callback arg and accept callback */
719                         tcp_arg(tpcb, &tnewpcb);
720                         tcp_accept(tpcb, nc_accept_callback);
721                 }
722                 else
723                 {
724                         tnewpcb = tpcb;
725                         tpcb = NULL;
726                         err = tcp_connect(tnewpcb, &remoteIP, portNO, nc_connected_callback);
727                         LWIP_ASSERT(("nc_init: tcp_connect failed"), err == ERR_OK);
728                 }
729         }
730         else
731         {
732                 if (listen)
733                         udp_recv(pcb, nc_udp_listen_recv_callback, NULL);
734                 else
735                 {
736                         err = udp_connect(pcb, &remoteIP, portNO);
737                         LWIP_ASSERT(("nc_init: udp_connect failed"), err == ERR_OK);
738                         //connected = TRUE;
739                         /* set udp recv callback */
740                         udp_recv(pcb, nc_udp_recv_callback, NULL);
741                 }
742         }
743
744         /* wait for connection to be established */
745         if (listen || !udp) {
746                 while (!connected) {
747                         if (rpp_sci_read_nb(1, &input) == SUCCESS) {
748                                 ncStop = TRUE;
749                                 break;
750                         }
751                         sys_check_timeouts();
752                         vTaskDelay(10); /* just because we have no other business here */
753                 }
754                 if (!udp && listen && tcp_close(tpcb) != ERR_OK) rpp_sci_printk("closing listening tcp pcb err\n");  /* close listening pcb */
755         }
756
757         /* mode handlers in loop, so we can jump out of it on error or finish and clean after us */
758         do {
759                 /*************************************** 1 mirror mode *****************************************/
760
761                 if (netLoop) { /* -m option */
762                         err = ERR_OK;
763                         /* send some data to opposite node so it knows its peer (this node) ; ATENTION if opposite node was not running in time this is send, then it wont get known this node's connection info */
764 /*          if(udp && !listen){
765                 payload = netbuf_alloc(localData,1);
766                 if(payload != NULL){
767                     input = 0;
768                     netbuf_take(localData,&input,1);
769                     netbuf_len(localData) = 1;
770                     if((err = netconn_send(newconn, localData)) != ERR_OK)break;
771                 }
772                 else
773                 {
774                     err = ERR_MEM;
775                     break;
776                 }
777             }*/
778                         /* register callback function which sends all the recevd data back to remote host */
779                         if (!udp)
780                                 tcp_recv(tnewpcb, nc_tmirror_callback);
781                         else
782                                 udp_recv(pcb, nc_umirror_callback, NULL);
783
784                         while (rpp_sci_read_nb(1, &input) != SUCCESS) {
785                                 sys_check_timeouts();
786                                 vTaskDelay(10);
787                         }
788                         break;
789                 }
790
791                 /*************************************** 2 testing mode *****************************************/
792
793                 if (test) { /* -d option; sends packets to the opposite node and doesn't receive anything */
794                         index = 0;
795                         char strbuf[13];
796                         int strlen;
797                         //netconn_set_recvtimeout(newconn, 1);
798                         while (index++ < 4294967295) {
799                                 /* allow user to interrupt sending */
800                                 if (rpp_sci_read_nb(1, &input) == SUCCESS) break;
801                                 strlen = sprintf(strbuf,"%d\r\n",index);
802                                 if (!udp) {
803                                         sys_check_timeouts();
804                                         if (tcp_write(tnewpcb, strbuf, strlen, TCP_WRITE_FLAG_COPY) != ERR_OK) {
805                                                 rpp_sci_printf("error writing to newpcb - tcp_write testing\n");
806                                                 break;
807                                         }
808                                         if (tcp_output(tnewpcb) != ERR_OK) { /* when we want to send data immediately */
809                                                 rpp_sci_printf("newpcb output err - tcp testing\n");
810                                                 break;
811                                         }
812                                 }
813                                 else
814                                 {
815                                         p = pbuf_alloc(PBUF_TRANSPORT, strlen, PBUF_RAM);
816                                         if (p == NULL) {
817                                                 rpp_sci_printf("error allocating pbuf - udp_send testing\n");
818                                                 continue;
819                                         }
820                                         if (pbuf_take(p, strbuf, strlen) != ERR_OK) {
821                                                 rpp_sci_printf("pbuf mem err (small pbuf) - udp_send testing\n");
822                                                 continue;
823                                         }
824                                         if (udp_send(pcb, p) != ERR_OK) {
825                                                 rpp_sci_printf("error sending to pcb - udp_send testing\n");
826                                                 continue;
827                                         }
828                                 }
829                         }
830                         break;
831                 }
832
833                 /*************************************** 3 interactive mode *****************************************/
834
835                 while (!ncStop) {
836                         if (!udp && tnewpcb->state != ESTABLISHED) {
837                                 ncStop = TRUE;
838                                 break;
839                         }
840                         if (rpp_sci_read_nb(1, &input) != SUCCESS) {
841                                 /* updating lwip timers here */
842                                 sys_check_timeouts();
843                                 continue;
844                         }
845
846                         // Backspace and Delete
847                         if (input == 8 || input == 127) {
848                                 if (buff_index > 0) {
849                                         buff_index--;
850                                         rpp_sci_putc('\b');
851                                         rpp_sci_putc(' ' );
852                                         rpp_sci_putc('\b');
853                                 }
854
855                                 // Line feed or Carriage return
856                         }
857                         else if (input == 10 || input == 13) {
858                                 in_buffer[buff_index] = 13;
859                                 buff_index++;
860                                 in_buffer[buff_index] = 10;
861                                 buff_index++;
862                                 flush = TRUE;
863                                 rpp_sci_putc('\r');
864                                 rpp_sci_putc('\n');
865
866                                 // If is any printable character
867                         }
868                         else if (isprint(input) || input == 9) {
869
870                                 // Store character and increment buffer index
871                                 in_buffer[buff_index] = input;
872                                 buff_index++;
873                                 rpp_sci_putc(input);
874
875                                 // Check if buffer is full and force flush
876                                 if (buff_index == BUF_SIZE - 3)
877                                         flush = TRUE;
878                                 // All other character stops nc
879                         }
880                         else {
881                                 ncStop = TRUE;
882                                 flush = TRUE;
883                         }
884
885                         if (flush) {
886                                 while (!udp && !ncStop && !sent) {
887                                         sys_check_timeouts();
888                                         vTaskDelay(10);
889                                 }
890                                 if (ncStop) break;
891                                 if (!udp) {
892                                         if (tcp_write(tnewpcb, in_buffer, buff_index, TCP_WRITE_FLAG_COPY) != ERR_OK) {
893                                                 rpp_sci_printf("error writing to newpcb - tcp_write\n");
894                                                 continue;
895                                         }
896                                         if (tcp_output(tnewpcb) != ERR_OK) { /* when we want to send data immediately */
897                                                 rpp_sci_printf("newpcb output err - tcp\n");
898                                                 continue;
899                                         }
900                                 }
901                                 else
902                                 {
903                                         p = pbuf_alloc(PBUF_TRANSPORT, buff_index, PBUF_RAM);
904                                         if (p == NULL) {
905                                                 rpp_sci_printf("error allocating pbuf - udp_send\n");
906                                                 continue;
907                                         }
908                                         if (pbuf_take(p, in_buffer, buff_index) != ERR_OK) {
909                                                 rpp_sci_printf("pbuf mem err (small pbuf) - udp_send\n");
910                                                 continue;
911                                         }
912                                         if (udp_send(pcb, p) != ERR_OK) {
913                                                 rpp_sci_printf("error sending to pcb - udp_send\n");
914                                                 continue;
915                                         }
916                                 }
917                                 // Reset variables
918                                 sent = FALSE;
919                                 buff_index = 0;
920                                 flush = FALSE;
921                         }
922                 }
923
924         } while (0);
925
926 /* close connection and clean */
927         if (!udp) {
928                 tcp_recv(tnewpcb, NULL);
929                 err = tcp_close(tnewpcb);
930                 if (err != ERR_OK) {
931                         rpp_sci_printf("newpcb closing error\n");
932                         /* closing failed, try again later */
933                         LWIP_DEBUGF(LWIP_DBG_ON, ("Error %s closing pcb=0x%08X\n", lwip_strerr(err), pcb));
934                         tcp_recv(tnewpcb, nc_recv_callback);
935                 }
936                 else {
937                         /* closing succeeded */
938                         tcp_arg(tnewpcb, NULL);
939                         tcp_sent(tnewpcb, NULL);
940                 }
941         }
942         else
943         {
944                 udp_disconnect(pcb);
945                 udp_remove(pcb);
946         }
947         buff_index = 0;
948 #endif /* if !NO_SYS */
949         return ERR_OK;
950 }
951
952 #endif  /* DOCGEN */
953
954 cmd_des_t const cmd_des_nc = {
955         0,CDESM_SPACE_SEP,
956         "ethnc","Start very simple netcat",
957
958         "### Command syntax ###\n"
959         "\n"
960         "     ethnc <IP> <PORT> [-p <PORT>] [-u] [-m [-t] | -d [-t]] [-c]\n"
961         "     ethnc -l <PORT> [-u] [-m [-t] | -d [-t]] [-c]\n"
962         "\n"
963         "### Description ###\n"
964         "\n"
965         "Netcat is a program which allows to communicate using TCP or UDP\n"
966         "protocols. First a connection is established by either:\n"
967         "\n"
968         "- connecting to a specified IP address and PORT (without option -l) or by\n"
969         "- listening for a new connection on a given PORT (with option -l).\n"
970         "\n"
971         "When no -u option is specified ethnc command works with TCP\n"
972         "connections. With -u option UDP communication is used. Listening for\n"
973         "connection on UDP means waiting for reception of any UDP datagram.\n"
974         "\n"
975         "Once the connection is established the command works in one of the\n"
976         "following modes:\n"
977         "\n"
978         "- interactive mode in which received data are forwarded to serial line and data received on serial line are sent to the connection when either new line is encountered or when internal buffer is full,\n"
979         "- sending of testing data (increasing ASCII formatted numbers) (option -d),\n"
980         "- looping of incoming data back to the connection's peer (option -m).\n"
981         "\n"
982         "Note: When trying to use a same local TCP port number multiple times\n"
983         "in a row (-l or -p options) there might be several minutes delay\n"
984         "before the port is available after closing the previous connection.\n"
985         "This situation is singled with ERROR 31.\n"
986         "\n"
987         "Other options:\n"
988         "\n"
989         "- -p specifies local port for outgoing connections.\n"
990         "- -u use UDP protocol instead of the default TCP.\n"
991         "- -t send and/or receive data in a background thread (works only with -d or -m options).\n"
992         "- -c stop all running background tasks\n"
993         "\n"
994         "### Examples ###\n"
995         "\n"
996         "Listen for incoming TCP connection on local port 2000:\n"
997         "     --> ethnc -l 2000\n"
998         "\n"
999         "Connect using TCP to address 192.168.247.15 to remote port 80 using local port 1500:\n"
1000         "     --> ethnc 192.168.247.15 80 -p 1500\n"
1001         "\n"
1002         "Send testing data to the remote node:\n"
1003         "     --> ethnc -d 192.168.247.2 1025\n"
1004         "\n"
1005         "Loop back all data coming from remote node's UDP port 1025:\n"
1006         "     --> ethnc -m -u 192.168.247.2 1025\n"
1007         "\n"
1008         "Wait for a TCP connection on local port 30000 and loop all incoming data\n"
1009         "back:\n"
1010         "     --> ethnc -l 30000 -m\n",
1011         CMD_HANDLER(cmd_do_init_nc), (void*)&cmd_list_nc
1012 };
1013
1014 /** List of commands for lwip, defined as external */
1015 cmd_des_t const *cmd_list_nc[] = {
1016         &cmd_des_nc,
1017         NULL
1018 };