Posted on

Multiple node monitoring/control via Python/netpp

Since scalability of the netpp node solution was advertised, one issue has turned into a FAQ: How to handle errors on loaded networks and traffic between multiple nodes?

Especially with UDP, plenty of scenarios can occur which can confuse all higher protocol layers: lost packets, reverse packet order, duplicate packets…

How to handle these errors, does the netpp layer take care of it all?

It doesn’t. The current strategy with UDP is: We want to see all errors. If we don’t, we’d rather switch to a TCP implementation.

In our test scenario we have, connected by a Gigabit Hub:

  • One Gigabit Ethernet capable client, one 100M client
  • Six netpp nodes

If the network is not completely jammed, the usual you would see is timeouts. In Python, these are simple IOError exceptions. If an illegal packet sequence is detected, a SystemError exception will be raised.

As a simple example, the script below will poll all detected hosts at highest frequency possible and cover IOError and SystemError exceptions with different recovery timings.

Note that there is no particular finer control for specific errors in Python. If required, these have to be handled on the C-API level.

import netpp
import time
import sys


hostlist = range(8, 15)


def init(hostlist):
    targets = []
    for h in hostlist:
        try:
            ip = "192.168.0.%d" % h
            d = netpp.connect("UDP:%s:2016" % ip)
            print "Target %s alive" % ip
            targets.append((h, d.sync()))
        except:
            print "Target %s down" % ip
            pass
        
    return targets


def poll(targets):
    for h, t in targets:
        rev = t.SysCtrl.ReleaseTag.get()
        print "Node %d : Class '%s' rev %s" % (h, t.name(), rev)
        l = t.LED.Red.get()
        l = not l
        t.LED.Red.set(l)
        print 40 * "-"

    l = True
    while 1:
        for h, t in targets:
            try:
                t.LED.Green.set(l)
                dataready = t.UART.RXREADY.get()
                if dataready:
                    print "> %s" % t.UART.RxData.get()
            except SystemError:
                print "Node %d: %s" % (h, sys.exc_info()[1])
                time.sleep(1.0)
            except IOError:
                print "Node %d: %s" % (h, sys.exc_info()[1])
                time.sleep(0.1)
        l = not l
        # time.sleep(0.05)

targets = init(hostlist)
poll(targets)

Script details

The script will just toggle the Green LED for each target and check if there’s input available on the UART. If you have the corresponding netpp node connected via USB serial, you can type in a character at the terminal and see it reported from the script.

Timeouts and sessions

UDP is session-less, therefore netpp handles the connectivity from peer to peer. By default, only two simultaneous connections (two clients) are supported. If a connection is lost, the netpp node will terminate it after a certain timeout, if a new connection is detected. This is signalled on the netpp node UART console by:

disconnect_timeout: c0a80002:49587

If the connection is lost from the netpp node side, for example via a reboot or long cable disconnect, the client may not detect that and keep sending queries. In this case, you might see the following error on the netpp node console:

QRY 55 NAK

(the 55 could be any other code).

In this case, the session would have to be reopened from the client:

d = netpp.connect(...)

FPGA goes cloudy

If you’re collecting data as simple as Temperature and Humidity, for instance, you might want to push the data to the cloud. This is also done using a simple Python script doing a HTTP get request to ThinkSpeak. Note the netpp node does not push the data, the script is running on an embedded Linux module.


Posted on

netpp node display

 

LCD 220×176 font display

Just as proof of concept, I up-ported the LCD-interface from the ‘beatrix’ SoC to the ‘dagobert’ netpp node default SoC configuration. This also introduces GPIO multiplexing options on port A, meaning, that a few pins have dedicated funcionality driven by an asynchronous bus engine with some extra decompression logic, tailored specifically for LCD screens. Since direct GPIO bit banging would burn a few more cycles and be slow, having a special interface definitely pays off (apart from DMA features, etc.)

The display controller of this OpenSmart variant has different addressing modes, so you can switch between landscape and portrait. However, there’s a catch: When trying to make use of the built-in scrolling feature, it turns out it is only supported for portrait mode, i.e. the shown landscape orientation would require to buffer the terminal content and redraw for each new line.

I have also tried to run a simple GUI toolkit as Achim Döblers µGUI. Due to its simple pixel-wise drawing API it is not very fast, but works ok for most purposes.

What is left to do is the touch screen implementation. This will only work on the ADC10 variant of the netpp node with populated msp430g2553. For now, touch screen is not required, so this task is not scheduled (no pun intended).

Other than that, the same techniques as mentioned in this post are used to save RAM resources using the SCACHE peripheral.