]> rtime.felk.cvut.cz Git - pes-rpp/rpp-test-sw.git/commitdiff
started statistic commands, NO_SYS nc version
authorJan Dolezal <pm.jenik@gmail.com>
Mon, 26 Aug 2013 13:21:07 +0000 (15:21 +0200)
committerJan Dolezal <pm.jenik@gmail.com>
Mon, 2 Sep 2013 10:30:45 +0000 (12:30 +0200)
.cproject
commands/cmd.c
commands/cmd_lwip.c
commands/cmd_netstats.c [new file with mode: 0644]
commands/cmd_netstats.h [new file with mode: 0644]
rpp-lib

index 72148ec658856b249e81955961f4c0573c508098..7b1dc7841a39be07501725133492a3b2e9f386c5 100644 (file)
--- a/.cproject
+++ b/.cproject
                                                                        <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/rpp-lib/lwip/src/include/ipv6}&quot;"/>
                                                                </option>
                                                                <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GCC.795138235" name="Enable support for GCC extensions (--gcc)" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GCC" value="true" valueType="boolean"/>
-                                                               <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEFINE.35615475" name="Pre-define NAME (--define, -D)" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEFINE" valueType="definedSymbols">
-                                                                       <listOptionValue builtIn="false" value="DEBUG"/>
-                                                                       <listOptionValue builtIn="false" value="LWIP_DEBUG"/>
-                                                               </option>
+                                                               <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEFINE.35615475" name="Pre-define NAME (--define, -D)" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEFINE" valueType="definedSymbols"/>
                                                                <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WARNING.1682379727" name="Treat diagnostic &lt;id&gt; as warning (--diag_warning, -pdsw)" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WARNING" valueType="stringList">
                                                                        <listOptionValue builtIn="false" value="225"/>
                                                                </option>
index fc42397b33dcc30009a7e7d1da8620195f093b03..a769d28af93acfa77c1a0f17b29fe474d1c0859e 100644 (file)
@@ -40,6 +40,7 @@
 #include "cmd_lin.h"
 #include "cmd_lout.h"
 #include "cmd_lwip.h"
+#include "cmd_netstats.h"
 #include "cmd_pin.h"
 #include "cmd_port.h"
 #include "cmd_sdram.h"
@@ -130,6 +131,7 @@ cmd_des_t const *cmd_list_main[]={
   CMD_DES_INCLUDE_SUBLIST(cmd_list_lin),
   CMD_DES_INCLUDE_SUBLIST(cmd_list_lout),
   CMD_DES_INCLUDE_SUBLIST(cmd_list_lwip),
+  CMD_DES_INCLUDE_SUBLIST(cmd_list_netstats),
   CMD_DES_INCLUDE_SUBLIST(cmd_list_pin),
   CMD_DES_INCLUDE_SUBLIST(cmd_list_port),
   CMD_DES_INCLUDE_SUBLIST(cmd_list_sdram),
index 1bab1db0b776453d67bef79cbe5dfa21f64d2498..63677c542031b175848f970776d66d47ea80db8a 100644 (file)
 #include <ctype.h>
 
 #include "rpp/rpp.h"
-#include "lwip/api.h" //netconn
 #include "lwip/udp.h"
+#if !NO_SYS
+#include "lwip/api.h" //netconn
+#else
+#include "lwip/timers.h" //for updating timers, when NO_SYS == 1
+#include "lwip/tcp.h"
+#include "lwip/tcp_impl.h"
+#endif
 
 #define INTERFACE_INSTANCE_NUMBER 0
 
@@ -118,7 +124,9 @@ void run_nc(void *arg){
        ip_addr_t remoteIP = nc_arg->remoteIP;
        boolean_t udp = nc_arg->udp, listen = nc_arg->listen, srcPortSpec = nc_arg->srcPortSpec, netLoop = nc_arg->netLoop, test = nc_arg->test;
        boolean_t thread = nc_arg->thread; /* variable controling whether this instance should run as thread */
+#if DEBUG
        uint8_t thread_inst = (taskNameNum-1); /* store number of this thread */
+#endif
        tasks_running++;
 
 
@@ -230,7 +238,7 @@ void run_nc(void *arg){
                if(test) /* -d option; sends packets to the opposite node and doesn't receive anything */
                {
                        index = 0;
-                       char strbuf[10];
+                       char strbuf[13];
                        int strlen;
                        //netconn_set_recvtimeout(newconn, 1);
                        while(!closeths && index++ < 4294967295){
@@ -444,8 +452,161 @@ void run_nc(void *arg){
                nc_arg->err = err; /* only user controlled task is in front */
        if(thread)vTaskDelete(NULL);
 }
+#else
+boolean_t connected;
+boolean_t sent;
+boolean_t ncStop;
+
+err_t nc_recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
+{
+    uint16_t index;
+    uint8_t *payload;
+       if(err == ERR_ABRT)
+       {
+               rpp_sci_printk((const char *) "recv abrt\n");
+               return ERR_ABRT;
+       }
+       /* print remote data to SCI */
+       while(p != NULL)
+       {
+           index = 0;
+           payload = p->payload;
+           while(index<p->len)
+           {
+               rpp_sci_printk((const char *) "%c",payload[index]);
+               index++;
+           }
+        p = p->next;
+       }
+    return ERR_OK;
+}
+
+void nc_udp_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
+{
+    uint16_t index;
+    uint8_t *payload;
+       /* print remote data to SCI */
+       while(p != NULL)
+       {
+           index = 0;
+           payload = p->payload;
+           while(index<p->len)
+           {
+               rpp_sci_printk((const char *) "%c",payload[index]);
+               index++;
+           }
+        p = p->next;
+       }
+    //pbuf_free(p);
+}
+
+void nc_udp_listen_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
+{
+       connected = TRUE;
+       err_t err = udp_connect(pcb, addr, port);
+    LWIP_ASSERT(("nc_init: udp_listen_connect failed"), err == ERR_OK);
+       udp_recv(pcb, nc_udp_recv_callback, NULL);
+       nc_udp_recv_callback(arg, pcb, p, addr, port);
+}
+
+void nc_err_callback(void *arg, err_t err)
+{
+       rpp_sci_printk((const char *) "err clbck\n");
+       LWIP_DEBUGF(LWIP_DBG_ON, ("nc_err: %s", lwip_strerr(err)));
+
+       ncStop = TRUE;
+}
+
+err_t nc_sent_callback(void *arg, struct tcp_pcb *pcb, u16_t len)
+{
+       sent = TRUE;
+       return ERR_OK;
+}
+
+err_t nc_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
+{
+       struct tcp_pcb **newone = arg;
+       *newone = newpcb; /* pass accepted connection to main app loop */
+
+       connected = TRUE;
+
+    /* Set up the various callback functions */
+    tcp_recv(newpcb, nc_recv_callback);
+    tcp_err(newpcb, nc_err_callback);
+    tcp_sent(newpcb, nc_sent_callback);
+
+    return ERR_OK;
+}
+
+err_t nc_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err)
+{
+
+    /* Set up the various callback functions */
+    tcp_recv(tpcb, nc_recv_callback);
+    tcp_err(tpcb, nc_err_callback);
+    tcp_sent(tpcb, nc_sent_callback);
+
+       connected = TRUE;
+       rpp_sci_printk((const char *) "connected\n");
+    return ERR_OK;
+}
+
+err_t nc_tmirror_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
+{
+       if(err == ERR_ABRT)
+       {
+               rpp_sci_printk((const char *) "recv abrt\n");
+               return ERR_ABRT;
+       }
+       while(p != NULL)
+       {
+               if(tcp_write(tpcb, p->payload, p->len, TCP_WRITE_FLAG_COPY)!=ERR_OK){
+               rpp_sci_printk((const char *) "error writing to newpcb - tcp_write\n");
+               return -1;
+       }
+       if(tcp_output(tpcb)!=ERR_OK){ /* when we want to send data immediately */
+               rpp_sci_printk((const char *) "newpcb output err - tcp\n");
+               return -1;
+       }
+           p = p->next;
+       }
+       return ERR_OK;
+}
+
+void nc_umirror_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
+{
+    struct pbuf *pbuf;
+       while(p != NULL)
+       {
+        pbuf = pbuf_alloc(PBUF_TRANSPORT, p->len, PBUF_RAM);
+        if(pbuf == NULL)
+        {
+               rpp_sci_printk((const char *) "error allocating pbuf - udp_send\n");
+               //p = p->next;
+               continue;
+        }
+        if(pbuf_take(pbuf, p->payload, p->len)!=ERR_OK)
+        {
+               rpp_sci_printk((const char *) "pbuf mem err (small pbuf) - udp_send\n");
+               continue;
+        }
+       if(udp_send (pcb, pbuf)!=ERR_OK)
+       {
+               rpp_sci_printk((const char *) "error sending to pcb - udp_send\n");
+               continue;
+       }
+        p = p->next;
+       }
+}
+
+
 #endif /* !NO_SYS */
 
+/*
+ * this function has two operational modes, depending on LwIP settings
+ * NO_SYS == 1 - this is for testing raw API, there is only one task working with IP stack allowed when using this mode
+ * NO_SYS == 0 - this is for testing netconn API, you can let more tasks to work with IP stack
+ */
 int cmd_do_init_nc(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
 {
     err_t err = ERR_OK;
@@ -453,13 +614,22 @@ int cmd_do_init_nc(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
        ip_addr_t remoteIP;
        boolean_t help = FALSE, udp = FALSE, listen = FALSE, netLoop = FALSE, test = FALSE, srcPortSpec = FALSE;
     uint8_t pindex;
-    uint8_t name[5] = "nc";
-    name[4] = '\0';
 
-       /* initialize arguments */
+       buff_index = 0;
+       /* initialize arguments and thread name */
 #if !NO_SYS
+    uint8_t name[5] = "nc";
+    name[4] = '\0';
        struct nc_arg nc_arg; /* create space for handing args to nc_run() */
        nc_arg.thread = FALSE;
+#else
+       uint8_t input = 0;
+    boolean_t flush = FALSE;
+    uint32_t index;
+    struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
+       struct tcp_pcb *tpcb, *tnewpcb;
+       struct udp_pcb *pcb;
+       struct pbuf *p; /* udp send */
 #endif
 
     /* examine parameters */
@@ -540,6 +710,7 @@ nc -l <port> -d [-u] [-t]
     /* determine srcPortNO from predefined value if not done yet (from argument given) */
     if(!srcPortSpec)
     {
+       //udp_new_port();
        srcPortNO = srcPort++;
     }
 
@@ -582,7 +753,286 @@ nc -l <port> -d [-u] [-t]
         return nc_arg.err;
     }
 #else /* raw LwIP API */
-    rpp_sci_printf((const char *) "nc does not support NO_SYS yet\r\n");
+    ncStop = FALSE;
+    connected = FALSE;
+    sent = TRUE;
+    if(udp)
+    {
+       pcb = udp_new();
+        LWIP_ASSERT(("nc_init: udp_new failed"), pcb != NULL);
+        if(pcb == NULL)return -1;
+        err = udp_bind(pcb, &(netif->ip_addr), srcPortNO);
+        CC_ASSERT(("nc_init: udp_bind failed: %s", lwip_strerr(err)), err == ERR_OK);
+        if(err != ERR_OK)return -1;
+    }
+    else
+    {
+       tpcb = tcp_new();
+        LWIP_ASSERT(("nc_init: tcp_new failed"), tpcb != NULL);
+        if(tpcb == NULL)return -1;
+        err = tcp_bind(tpcb, &(netif->ip_addr), srcPortNO);
+        CC_ASSERT(("nc_init: tcp_bind failed: %s", lwip_strerr(err)), err == ERR_OK);
+        if(err != ERR_OK)return -1;
+    }
+
+    if(!udp)
+    {
+       if(listen)
+       {
+            tpcb = tcp_listen(tpcb);
+            LWIP_ASSERT(("nc_init: tcp_listen failed"), tpcb != NULL);
+            /* initialize callback arg and accept callback */
+            tcp_arg(tpcb, &tnewpcb);
+            tcp_accept(tpcb, nc_accept_callback);
+       }
+       else
+       {
+               tnewpcb = tpcb;
+               tpcb = NULL;
+               err = tcp_connect(tnewpcb, &remoteIP, portNO, nc_connected_callback);
+            LWIP_ASSERT(("nc_init: tcp_connect failed"), err == ERR_OK);
+       }
+    }
+    else
+    {
+       if(listen)
+       {
+               udp_recv(pcb, nc_udp_listen_recv_callback, NULL);
+       }
+       else
+       {
+               err = udp_connect(pcb, &remoteIP, portNO);
+            LWIP_ASSERT(("nc_init: udp_connect failed"), err == ERR_OK);
+               //connected = TRUE;
+               /* set udp recv callback */
+               udp_recv(pcb, nc_udp_recv_callback, NULL);
+       }
+    }
+
+    /* wait for connection to be established */
+    if(listen || !udp)
+    {
+        while(!connected)
+        {
+               if(rpp_sci_read_nb(1, &input) == SUCCESS)
+               {
+                   ncStop = TRUE;
+                   break;
+               }
+               sys_check_timeouts();
+               vTaskDelay(10); /* just because we have no other business here */
+        }
+        if(!udp && listen && tcp_close(tpcb) != ERR_OK)rpp_sci_printk((const char *) "closing listening tcp pcb err\n"); /* close listening pcb */
+    }
+
+    /* mode handlers in loop, so we can jump out of it on error or finish and clean after us */
+    do{
+        /*************************************** 1 mirror mode *****************************************/
+
+       if(netLoop) /* -m option */
+       {
+               err = ERR_OK;
+               /* 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 */
+/*             if(udp && !listen){
+                       payload = netbuf_alloc(localData,1);
+                       if(payload != NULL){
+                               input = 0;
+                       netbuf_take(localData,&input,1);
+                       netbuf_len(localData) = 1;
+                       if((err = netconn_send(newconn, localData)) != ERR_OK)break;
+               }
+               else
+               {
+                       err = ERR_MEM;
+                    break;
+               }
+               }*/
+               /* register callback function which sends all the recevd data back to remote host */
+               if(!udp)
+               {
+                       tcp_recv(tnewpcb, nc_tmirror_callback);
+               }
+               else
+               {
+                       udp_recv(pcb, nc_umirror_callback, NULL);
+               }
+
+               while(rpp_sci_read_nb(1, &input) != SUCCESS)
+               {
+                       sys_check_timeouts();
+                       vTaskDelay(10);
+               }
+            break;
+       }
+
+        /*************************************** 2 testing mode *****************************************/
+
+       if(test) /* -d option; sends packets to the opposite node and doesn't receive anything */
+       {
+               index = 0;
+               char strbuf[13];
+               int strlen;
+               //netconn_set_recvtimeout(newconn, 1);
+               while(index++ < 4294967295){
+                /* allow user to interrupt sending */
+                       if(rpp_sci_read_nb(1, &input) == SUCCESS)break;
+               strlen = sprintf(strbuf,"%d\r\n",index);
+                if(!udp)
+               {
+                       sys_check_timeouts();
+                       if(tcp_write(tnewpcb, strbuf, strlen, TCP_WRITE_FLAG_COPY)!=ERR_OK){
+                               rpp_sci_printf((const char *) "error writing to newpcb - tcp_write testing\n");
+                               break;
+                       }
+                       if(tcp_output(tnewpcb)!=ERR_OK){ /* when we want to send data immediately */
+                               rpp_sci_printf((const char *) "newpcb output err - tcp testing\n");
+                               break;
+                       }
+               }
+               else
+               {
+                    p = pbuf_alloc(PBUF_TRANSPORT, strlen, PBUF_RAM);
+                    if(p == NULL)
+                    {
+                               rpp_sci_printf((const char *) "error allocating pbuf - udp_send testing\n");
+                               continue;
+                    }
+                    if(pbuf_take(p, strbuf, strlen)!=ERR_OK)
+                    {
+                               rpp_sci_printf((const char *) "pbuf mem err (small pbuf) - udp_send testing\n");
+                               continue;
+                    }
+                       if(udp_send (pcb, p)!=ERR_OK)
+                       {
+                               rpp_sci_printf((const char *) "error sending to pcb - udp_send testing\n");
+                               continue;
+                       }
+               }
+               }
+               break;
+       }
+
+        /*************************************** 3 interactive mode *****************************************/
+
+       while(!ncStop)
+       {
+               if(!udp && tnewpcb->state != ESTABLISHED)
+               {
+                   ncStop = TRUE;
+                   break;
+               }
+               if(rpp_sci_read_nb(1, &input) != SUCCESS) {
+                       /* updating lwip timers here */
+                       sys_check_timeouts();
+                       continue;
+               }
+
+            // Backspace and Delete
+            if(input == 8 || input == 127) {
+                if(buff_index > 0) {
+                    buff_index--;
+                    rpp_sci_putc('\b');
+                    rpp_sci_putc(' ' );
+                    rpp_sci_putc('\b');
+                }
+
+            // Line feed or Carriage return
+            } else if(input == 10 || input == 13) {
+               in_buffer[buff_index] = 13;
+               buff_index++;
+               in_buffer[buff_index] = 10;
+               buff_index++;
+                flush = TRUE;
+                rpp_sci_putc('\r');
+                rpp_sci_putc('\n');
+
+            // If is any printable character
+            } else if(isprint(input) || input == 9) {
+
+                // Store character and increment buffer index
+                in_buffer[buff_index] = input;
+                buff_index++;
+                rpp_sci_putc(input);
+
+                // Check if buffer is full and force flush
+                if(buff_index == BUF_SIZE - 3) {
+                    flush = TRUE;
+                }
+            // All other character stops nc
+            } else {
+               ncStop = TRUE;
+               flush = TRUE;
+            }
+
+            if(flush)
+            {
+               while(!udp && !ncStop && !sent)
+               {
+                       sys_check_timeouts();
+                       vTaskDelay(10);
+               }
+               if(ncStop)break;
+                if(!udp)
+               {
+                       if(tcp_write(tnewpcb, in_buffer, buff_index, TCP_WRITE_FLAG_COPY)!=ERR_OK){
+                               rpp_sci_printf((const char *) "error writing to newpcb - tcp_write\n");
+                               continue;
+                       }
+                       if(tcp_output(tnewpcb)!=ERR_OK){ /* when we want to send data immediately */
+                               rpp_sci_printf((const char *) "newpcb output err - tcp\n");
+                               continue;
+                       }
+               }
+               else
+               {
+                    p = pbuf_alloc(PBUF_TRANSPORT, buff_index, PBUF_RAM);
+                    if(p == NULL)
+                    {
+                               rpp_sci_printf((const char *) "error allocating pbuf - udp_send\n");
+                               continue;
+                    }
+                    if(pbuf_take(p, in_buffer, buff_index)!=ERR_OK)
+                    {
+                               rpp_sci_printf((const char *) "pbuf mem err (small pbuf) - udp_send\n");
+                               continue;
+                    }
+                       if(udp_send (pcb, p)!=ERR_OK)
+                       {
+                               rpp_sci_printf((const char *) "error sending to pcb - udp_send\n");
+                               continue;
+                       }
+               }
+                // Reset variables
+               sent = FALSE;
+                buff_index = 0;
+                flush = FALSE;
+            }
+       }
+
+    }while(0);
+
+/* close connection and clean */
+       if(!udp)
+       {
+               tcp_recv(tnewpcb, NULL);
+               err = tcp_close(tnewpcb);
+               if (err != ERR_OK) {
+               rpp_sci_printf((const char *) "newpcb closing error\n");
+                   /* closing failed, try again later */
+                   LWIP_DEBUGF(LWIP_DBG_ON, ("Error %s closing pcb=0x%08X\n", lwip_strerr(err), pcb));
+                   tcp_recv(tnewpcb, nc_recv_callback);
+               } else {
+                   /* closing succeeded */
+                   tcp_arg(tnewpcb, NULL);
+                   tcp_sent(tnewpcb, NULL);
+               }
+       }
+       else
+       {
+               udp_disconnect(pcb);
+               udp_remove(pcb);
+       }
+    buff_index = 0;
 #endif
     return ERR_OK;
 }
diff --git a/commands/cmd_netstats.c b/commands/cmd_netstats.c
new file mode 100644 (file)
index 0000000..3c2bbe1
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2012-2013 Czech Technical University in Prague
+ *
+ * Created on: Aug 23, 2013
+ *
+ * Authors:
+ *     - Jan Dolezal <pm.jenik@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * File : cmd_netstats.c
+ *
+ * Abstract:
+ *     This file contains commands for net statistics (ethernet interface and LwIP)
+ *
+ */
+
+#include "cmd_netstats.h"
+
+#ifndef DOCGEN
+
+#include "rpp/rpp.h"
+#include "drv/emac.h"
+#include "lwip/opt.h"
+
+#define INTERFACE_INSTANCE_NUMBER 0
+
+
+/*      --- EMAC DESCRIPTOR FORMAT ---
+ *                                         bit fields
+ * WORD   |
+ * OFFSET | 31                               16 | 15                                 0
+ * ------------------------------------------------------------------------------------
+ *    0   |                         *Next Descriptor Pointer
+ *    1   |                           *Data Buffer Pointer
+ *    2   |            Buffer Offset            |            Buffer Length
+ *    3   |                Flags                |            Packet Length
+ *    4   |                                  *pbuf
+ */
+
+boolean_t bd_SOP(volatile struct emac_tx_bd *bufferDescriptor)
+{
+       return (bufferDescriptor->flags_pktlen & EMAC_DSC_FLAG_SOP);
+}
+
+boolean_t bd_EOP(volatile struct emac_tx_bd *bufferDescriptor)
+{
+       return (bufferDescriptor->flags_pktlen & EMAC_DSC_FLAG_EOP);
+}
+
+boolean_t bd_OWNER(volatile struct emac_tx_bd *bufferDescriptor)
+{
+       return (bufferDescriptor->flags_pktlen & EMAC_DSC_FLAG_OWNER);
+}
+
+boolean_t bd_EOQ(volatile struct emac_tx_bd *bufferDescriptor)
+{
+       return (bufferDescriptor->flags_pktlen & EMAC_DSC_FLAG_EOQ);
+}
+
+uint32_t bd_addr(uint16_t bd_num)
+{
+       return EMAC_CTRL_RAM_BASE_m(0) + bd_num*sizeof(struct emac_tx_bd);
+}
+
+volatile struct emac_tx_bd *findPreviousBD(volatile struct emac_tx_bd *bufferDescriptor)
+{
+       volatile struct emac_tx_bd *temporary = bufferDescriptor - 1;
+
+       /* first try space before given bd */
+       if((uint32_t) temporary >= EMAC_CTRL_RAM_BASE_m(0) && temporary->next == bufferDescriptor)
+               return temporary;
+       temporary = bufferDescriptor->next;
+    while(temporary != bufferDescriptor && temporary != NULL)
+    {
+       if(temporary->next == bufferDescriptor)
+               return temporary;
+       temporary = (temporary + 1); /* going through memory, if you want to go through bd chains put here 'temporary = temporary->next;' */
+       if( (uint32_t)(temporary+1) > EMAC_CTRL_RAM_BASE_m(0)+SIZE_EMAC_CTRL_RAM){ /* when out of CPPI RAM */
+               temporary = (struct emac_tx_bd *) EMAC_CTRL_RAM_BASE_m(0); /* continue scanning from the beginning */
+       }
+    }
+       return (struct emac_tx_bd *)-1; /* not found */
+}
+
+void print_bd_content(volatile struct emac_tx_bd *bufferDescriptor, boolean_t humanReadable)
+{
+    uint16_t data;
+    rpp_sci_printf((const char *) "Buffer Descriptor at 0x%08x\n", bufferDescriptor);
+    rpp_sci_printf((const char *) "Next BD:\t0x%08x\n", bufferDescriptor->next);
+    rpp_sci_printf((const char *) "Data ptr:\t0x%08x\n", bufferDescriptor->bufptr);
+    rpp_sci_printf((const char *) "Buf offset:\t%d\tBuf length:\t%d\n", (bufferDescriptor->bufoff_len >> 16), (bufferDescriptor->bufoff_len & 0xffff));
+    if(!humanReadable)
+    {
+    rpp_sci_printf((const char *) "Flags:\t\t0x%04x\t", (bufferDescriptor->flags_pktlen >> 16));
+    }
+    else
+    {
+    data = bufferDescriptor->flags_pktlen;
+    rpp_sci_printf((const char *) "Flags:\t%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n", (data & EMAC_DSC_FLAG_SOP)?"SOP":"", (data & EMAC_DSC_FLAG_EOP)?"EOP":"", (data & EMAC_DSC_FLAG_OWNER)?"OWNER":"", (data & EMAC_DSC_FLAG_EOQ)?"EOQ":"", (data & EMAC_DSC_FLAG_TDOWNCMPLT)?"TDWN":"", (data & EMAC_DSC_FLAG_PASSCRC)?"PSCRC":"", (data & EMAC_DSC_FLAG_JABBER)?"JBR":"", (data & EMAC_DSC_FLAG_OVERSIZE)?"OVSZ":"", (data & EMAC_DSC_FLAG_FRAGMENT)?"FRGM":"", (data & EMAC_DSC_FLAG_UNDERSIZED)?"UNSZ":"", (data & EMAC_DSC_FLAG_CONTROL)?"CTRL":"", (data & EMAC_DSC_FLAG_OVERRUN)?"OVRUN":"", (data & EMAC_DSC_FLAG_CODEERROR)?"CODEERR":"", (data & EMAC_DSC_FLAG_ALIGNERROR)?"ALGNERR":"", (data & EMAC_DSC_FLAG_CRCERROR)?"CRCERR":"", (data & EMAC_DSC_FLAG_NOMATCH)?"NOMATCH":"");
+    }
+    rpp_sci_printf((const char *) "Pkt length:\t%d\n", (bufferDescriptor->flags_pktlen & 0xffff));
+    rpp_sci_printf((const char *) "Pbuf ptr:\t0x%08x\n", bufferDescriptor->pbuf);
+}
+
+/*
+ * mode: 0 flags -> param says which flag (0-15)
+ *       1 bd->next == NULL, no param
+ */
+void print_bds_state(uint8_t mode, uint8_t param)
+{
+       volatile struct emac_tx_bd *bufferDescriptor = (struct emac_tx_bd *) EMAC_CTRL_RAM_BASE_m(0);
+       uint16_t index = 0;
+       rpp_sci_printf((const char *) "TX:");
+       while(index < 409)
+       {
+               if(!(index%10)){
+                       rpp_sci_printf((const char *) " ");
+                       if(!(index%20))rpp_sci_printf((const char *) "\n");
+               }
+               if(index == 204){
+                       rpp_sci_printf((const char *) "\nRX: ");
+               }
+           if      (mode == 0){
+            if(bufferDescriptor->flags_pktlen & ((1 << 15) >> (param%16))){
+               rpp_sci_printf((const char *) "f");
+            }else{
+               rpp_sci_printf((const char *) ".");
+            }
+           }else if(mode == 1){
+            if(bufferDescriptor->next == NULL){
+               rpp_sci_printf((const char *) "0");
+            }else{
+               rpp_sci_printf((const char *) ".");
+            }
+           }else return;
+           bufferDescriptor++;
+           index++;
+       }
+       rpp_sci_printf((const char *) "\n");
+}
+
+#if RPP_ETH_STATS
+void print_tx_channel_stat()
+{
+       rpp_sci_printf((const char *) "Transmit:\n");
+       rpp_sci_printf((const char *) "\t\tbeforeHandled\tafterHandled\n");
+       rpp_sci_printf((const char *) "active_tail:\t0x%08x\t0x%08x\n",
+                       beforeHandled.active_tail, afterHandled.active_tail);
+       rpp_sci_printf((const char *) "free_head:\t0x%08x\t0x%08x\n",
+                       beforeHandled.free_head, afterHandled.free_head);
+       rpp_sci_printf((const char *) "nxt_bd_to_proc:\t0x%08x\t0x%08x\n\n",
+               beforeHandled.next_bd_to_process, afterHandled.next_bd_to_process);
+}
+
+void print_rx_channel_stat()
+{
+       rpp_sci_printf((const char *) "Receive:\n");
+       rpp_sci_printf((const char *) "\t\tbeforeRecv\tafterRecv\n");
+       rpp_sci_printf((const char *) "active_head:\t0x%08x\t0x%08x\n",
+                       beforeRecv.active_head, afterRecv.active_head);
+       rpp_sci_printf((const char *) "active_tail:\t0x%08x\t0x%08x\n",
+                       beforeRecv.active_tail, afterRecv.active_tail);
+       rpp_sci_printf((const char *) "free_head:\t0x%08x\t0x%08x\n",
+                       beforeRecv.free_head, afterRecv.free_head);
+       rpp_sci_printf((const char *) "freed_pbuf_len:\t%d\t\t%d\n\n",
+                       beforeRecv.freed_pbuf_len, afterRecv.freed_pbuf_len);
+}
+
+void printStatistics()
+{
+       rpp_sci_printf((const char *) "BDs:\t\tTX\tRX\n");
+       rpp_sci_printf((const char *) "NO of filled PKTs:\t%d\t%d",filledTXPKTs,filledRXPKTs);
+       rpp_sci_printf((const char *) "\n");
+       rpp_sci_printf((const char *) "NO of sent PKTs:\t%d\t%d",handledTXPKTs,handledRXPKTs);
+       rpp_sci_printf((const char *) "\n");
+       rpp_sci_printf((const char *) "NO of filled BDs:\t%d\t%d",filledTXbds,filledRXbds);
+       rpp_sci_printf((const char *) "\n");
+       rpp_sci_printf((const char *) "NO of sent BDs:\t%d\t%d",handledTXbds,handledRXbds);
+       rpp_sci_printf((const char *) "\n");
+       rpp_sci_printf((const char *) "NO of runs of ISR:\t%d\t%d",countEMACCore0TxIsr,countEMACCore0RxIsr);
+       rpp_sci_printf((const char *) "\n");
+       rpp_sci_printf((const char *) "\n");
+
+       rpp_sci_printf((const char *) "PBUFs:\t\tTX\tRX\n");
+       rpp_sci_printf((const char *) "PBUF Chains prepared:\t%d\t%d",preparedTxPBUFChains,preparedRxPBUFChains);
+       rpp_sci_printf((const char *) "\n");
+       rpp_sci_printf((const char *) "PBUFs prepared:\t%d\t%d",preparedTxPBUFs,preparedRxPBUFs);
+       rpp_sci_printf((const char *) "\n");
+       rpp_sci_printf((const char *) "PBUF Chains filled:\t%d\t%d",filledTxPBUFChains,filledRxPBUFChains);
+       rpp_sci_printf((const char *) "\n");
+       rpp_sci_printf((const char *) "PBUFs filled:\t%d\t%d",filledTxPBUFs,filledRxPBUFs);
+       rpp_sci_printf((const char *) "\n");
+       rpp_sci_printf((const char *) "\n");
+}
+#endif
+
+#define BUF_SIZE 15
+
+unsigned long readNum(uint8_t minamount, uint8_t maxamount, boolean_t hex){
+       unsigned long out = 0;
+       uint8_t input_buffer[BUF_SIZE];
+       uint8_t buf_index = 0;
+       uint8_t input;
+    do{
+       input = rpp_sci_getc();
+       if(input == '\b' && buf_index>0){
+               input_buffer[buf_index] = '\0';
+               buf_index--;
+               echo('\b');
+               echo( ' ');
+               echo('\b');
+       }else if(buf_index>=maxamount){
+               continue;
+       }else if(input <= '9' && input >= '0'){
+               input_buffer[buf_index] = input - '0';
+               echo(input);
+               buf_index++;
+       }else if(hex && (input <= 'f' && input >= 'a')){
+               input_buffer[buf_index] = input - ('a' - 10);
+               echo(input);
+               buf_index++;
+       }else if(hex && (input <= 'F' && input >= 'A')){
+               input_buffer[buf_index] = input - ('A' - 10);
+               echo((input + ('a' - 'A')));
+               buf_index++;
+       }
+    }while( (input != '\r' && input != '\n' && buf_index<BUF_SIZE) || buf_index<minamount);
+    input = 0; /* use as index */
+    while(input < buf_index){
+       if(hex){
+               out = (out << 4) + input_buffer[input];
+       }else{
+               out = (out*10) + input_buffer[input];
+       }
+       input++;
+    }
+    return out;
+}
+
+int cmd_do_bufferdescriptors(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
+{
+       uint8_t input;
+       volatile struct emac_tx_bd *bufferDescriptor;
+       boolean_t run = TRUE;
+       struct netif *netif = rpp_eth_get_netif(INTERFACE_INSTANCE_NUMBER);
+       if(netif == NULL)
+       {
+               rpp_sci_printf((const char *) "netif err\n");
+               return -1;
+       }
+
+       while(run){
+               input = rpp_sci_getc();
+
+               if(input == 'b'){ /* print buffer descriptor at given address */
+                       rpp_sci_printf((const char *) "-? 0x");
+                       bufferDescriptor = (struct emac_tx_bd *) readNum(8,8,TRUE);
+                       rpp_sci_printf((const char *) "\n");
+                       /* check it fits EMAC CPPI RAM */
+                       /*if(bufferDescriptor >= EMAC_CTRL_RAM_BASE_m(INTERFACE_INSTANCE_NUMBER) && (bufferDescriptor + sizeof(struct emac_tx_bd)) <= EMAC_CTRL_RAM_BASE_m(INTERFACE_INSTANCE_NUMBER) + SIZE_EMAC_CTRL_RAM)
+                       {*/
+                               print_bd_content(bufferDescriptor, FALSE);
+                       /*}
+                       else
+                       {
+                               rpp_sci_printf((const char *) "address not from BD CPPI RAM range\n");
+                       }*/
+                       while(1){
+                               input = rpp_sci_getc();
+                               if      (input == 'n'){ /* next */
+                                       bufferDescriptor = bufferDescriptor->next;
+                                       if(bufferDescriptor != NULL){
+                                               print_bd_content(bufferDescriptor, FALSE);
+                                       }else{
+                                               rpp_sci_printf((const char *) "NULL\n");
+                                               break;
+                                       }
+                               }else if(input == 'p'){ /* previous */
+                                       bufferDescriptor = findPreviousBD(bufferDescriptor);
+                                       if((int32_t)bufferDescriptor != -1)
+                                       {
+                        if(bufferDescriptor == NULL){
+                                               rpp_sci_printf((const char *) "NULL\n");
+                                               break;
+                        }else{
+                               print_bd_content(bufferDescriptor, FALSE);
+                        }
+                                       }
+                                       else
+                                       {
+                                               rpp_sci_printf((const char *) "not found\n");
+                                               break;
+                                       }
+                               }else if(input == 'r'){ /* reprint */
+                                       if((int32_t)bufferDescriptor == -1 || bufferDescriptor == NULL)break;
+                    print_bd_content(bufferDescriptor, FALSE);
+                               }else break;
+                       }
+               }
+
+               if      (input == 'q'){ /* quit */
+                       run = FALSE;
+                       continue;
+               }
+#if RPP_ETH_STATS
+               else if(input == 's'){ /* general statistics */
+                       printStatistics();
+               }else if(input == 't'){ /* print tx channel */
+                       print_tx_channel_stat();
+                       continue;
+               }else if(input == 'r'){ /* print rx channel */
+                       print_rx_channel_stat();
+                       continue;
+               }
+#endif
+               else if(input == 'a'){ /* autocheck consistency of buffer descriptors */
+
+               }else if(input == 'o'){ /* overview */
+            uint8_t mode = rpp_sci_getc() - '0';
+            uint8_t param = rpp_sci_getc() - '0';
+            print_bds_state(mode, param);
+               }else if(input == 'c'){ /* convert */
+                       rpp_sci_printf((const char *) "0x%08x", bd_addr((uint16_t)readNum(1, 3, FALSE)));
+               }
+       }
+
+    return ERR_OK;
+}
+
+int cmd_do_dhcp(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
+{
+    rpp_sci_printf((const char *) "not implemented yet.");
+    return ERR_OK;
+}
+
+#if LWIP_STATS_DISPLAY
+int cmd_do_lwip(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
+{
+       rpp_sci_printf((const char *) "not implemented yet.");
+       void stats_display();
+       /*
+       void stats_display_proto(struct stats_proto *proto, const char *name);
+       void stats_display_igmp(struct stats_igmp *igmp, const char *name);
+       void stats_display_mem(struct stats_mem *mem, const char *name);
+       void stats_display_memp(struct stats_mem *mem, int index);
+       void stats_display_sys(struct stats_sys *sys);*/
+    return ERR_OK;
+}
+#endif
+
+#endif /* DOCGEN */
+
+cmd_des_t const cmd_des_bufferdescriptors={
+    0,0,
+    "bd","Examine emac buffer descriptors",
+
+    "=== Command syntax ===\n"
+    "\n"
+    "   bd\n"
+    "\n"
+    "=== Description ===\n"
+    "After startup you use keys to control what will be done.\n"
+    "  q - quit\n"
+    "  s - general statistics\n"
+    "  t - transmit channel status\n"
+    "  r - receive channel status\n"
+    "  b - after giving address of bd it prints bd content\n"
+    "  a - checks consistency of buffer descriptors\n"
+    "\n"
+    "\n"
+    "=== Example ===\n"
+    "\n"
+    "   --> bd\n"
+    "   \n",
+    CMD_HANDLER(cmd_do_bufferdescriptors), (void *)&cmd_list_netstats
+};
+
+cmd_des_t const cmd_des_dhcp={
+    0,0,
+    "dhcp","Prints and controls DHCP",
+
+    "=== Command syntax ===\n"
+    "\n"
+    "   dhcp\n"
+    "\n"
+    "=== Description ===\n"
+    "\n"
+    "\n"
+    ".\n"
+    "\n"
+    "=== Example ===\n"
+    "\n"
+    "   --> dhcp\n"
+    "   \n",
+    CMD_HANDLER(cmd_do_dhcp), (void *)&cmd_list_netstats
+};
+
+#if LWIP_STATS_DISPLAY
+cmd_des_t const cmd_des_lwip={
+    0,0,
+    "lwip","Prints statistics for the LwIP stack",
+
+    "=== Command syntax ===\n"
+    "\n"
+    "   lwip\n"
+    "\n"
+    "=== Description ===\n"
+    "\n"
+    "\n"
+    ".\n"
+    "\n"
+    "=== Example ===\n"
+    "\n"
+    "   --> lwip\n"
+    "   \n",
+    CMD_HANDLER(cmd_do_lwip), (void *)&cmd_list_netstats
+};
+#endif
+
+/** List of commands for lwip, defined as external */
+cmd_des_t const *cmd_list_netstats[]={
+  &cmd_des_bufferdescriptors,
+  &cmd_des_dhcp,
+#if LWIP_STATS_DISPLAY
+  &cmd_des_lwip,
+#endif
+  NULL
+};
+
diff --git a/commands/cmd_netstats.h b/commands/cmd_netstats.h
new file mode 100644 (file)
index 0000000..ae12a61
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * cmd_netstats.h
+ *
+ *  Created on: 23.8.2013
+ *      Author: Jan Doležal
+ */
+
+#ifndef CMD_NETSTATS_H_
+#define CMD_NETSTATS_H_
+
+#include "cmdproc.h"
+
+#define echo(x) rpp_sci_putc(x)
+
+extern cmd_des_t const *cmd_list_netstats[];
+
+#endif /* CMD_NETSTATS_H_ */
diff --git a/rpp-lib b/rpp-lib
index 32fffc216a30394bfedd3a3b20a5c2f42afa8a10..a4d0cb921de99b9a39c4a96b570c5ec184e9c3e0 160000 (submodule)
--- a/rpp-lib
+++ b/rpp-lib
@@ -1 +1 @@
-Subproject commit 32fffc216a30394bfedd3a3b20a5c2f42afa8a10
+Subproject commit a4d0cb921de99b9a39c4a96b570c5ec184e9c3e0