| From cb38f06f84e8d3c1e021265d40a21bc16b5a8a44 Mon Sep 17 00:00:00 2001 |
| From: Ravi kumar Veeramally <ravikumar.veeramally@linux.intel.com> |
| Date: Fri, 9 Jun 2017 13:08:52 +0300 |
| Subject: [PATCH] Added CoAP support for Sparrow Border Router |
| |
| Sparrow border router communicates with only TLV messages. But |
| there are other implementations which does not support TLV. |
| Support added with generic CoAP based commands to retrieve |
| RPL and IPv6 information with CoAP commands. Also supported |
| LED's control methods. |
| |
| Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@linux.intel.com> |
| --- |
| examples/sparrow/wsdemoserver.py | 4 +- |
| examples/sparrow/wspcoap.py | 81 +++++++++++++++++++++++++++ |
| examples/sparrow/wspnodes.py | 38 +++++++------ |
| examples/sparrow/www/index.html | 12 ++++ |
| products/sparrow-border-router/project-conf.h | 3 + |
| tools/sparrow/deviceserver.py | 1 + |
| 6 files changed, 120 insertions(+), 19 deletions(-) |
| create mode 100644 examples/sparrow/wspcoap.py |
| |
| diff --git a/examples/sparrow/wsdemoserver.py b/examples/sparrow/wsdemoserver.py |
| index 8db1db7..67127fa 100755 |
| --- a/examples/sparrow/wsdemoserver.py |
| +++ b/examples/sparrow/wsdemoserver.py |
| @@ -40,7 +40,7 @@ DEBUG = 0 |
| |
| import sys, subprocess, thread, string, tlvlib, socket, binascii |
| from SimpleWebSocketServer import WebSocket, SimpleWebSocketServer |
| -import json, deviceserver, struct, wspserial, wsptlvs, wspnodes |
| +import json, deviceserver, struct, wspserial, wsptlvs, wspnodes, wspcoap |
| import httpd |
| |
| # Some global vaiables |
| @@ -304,5 +304,5 @@ if __name__ == "__main__": |
| print "Starting demo server" |
| setup_state() |
| server = SimpleWebSocketServer('', 8001, DemoSocket) |
| - plugins = plugins + [wspserial.SerialCommands(), wsptlvs.TLVCommands(), wspnodes.NodeCommands()] |
| + plugins = plugins + [wspserial.SerialCommands(), wsptlvs.TLVCommands(), wspnodes.NodeCommands(), wspcoap.CoAPCommands()] |
| server.serveforever() |
| diff --git a/examples/sparrow/wspcoap.py b/examples/sparrow/wspcoap.py |
| new file mode 100644 |
| index 0000000..a1b2899 |
| --- /dev/null |
| +++ b/examples/sparrow/wspcoap.py |
| @@ -0,0 +1,81 @@ |
| +import wsplugin, thread, subprocess, json, re, os.path |
| + |
| +def coap_is_supported(): |
| + return os.path.isfile("/home/rveerama/src/libcoap-develop/examples/coap-client") |
| + |
| +def coap_get(ws, uri): |
| + ws.stop = False |
| + p=subprocess.Popen(["/home/rveerama/src/libcoap-develop/examples/coap-client", "-m", "get", uri], |
| + stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| + data = "" |
| + try: |
| + while not ws.stop: |
| + line = p.stdout.readline() |
| + if line == '': break |
| + data = data + line |
| + except Exception as e: |
| + print e |
| + print "CoAP Unexpected error:", sys.exc_info()[0] |
| + p.terminate() |
| + return data |
| + |
| +# This assumes that data is ascii! |
| +def coap_put(ws, uri, data): |
| + ws.stop = False |
| + p=subprocess.Popen(["/home/rveerama/src/libcoap-develop/examples/coap-client", "-e" + data, |
| + "-m", "put", uri], |
| + stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| + line = "" |
| + try: |
| + while not ws.stop: |
| + line = p.stdout.readline() |
| + if line == '': break |
| + print line |
| + except Exception as e: |
| + print e |
| + print "CoAP Unexpected error:", sys.exc_info()[0] |
| + p.terminate() |
| + return line |
| + |
| +def coap_check(ws): |
| + if not coap_is_supported(): |
| + print "Error: can not find libcoap at /home/rveerama/src/libcoap-develop/examples/coap-client" |
| + ws.sendMessage(json.dumps({"error":"Can not find libcoap. Please install libcoap in the server and try again."})) |
| + return False |
| + return True |
| + |
| +# The plugin class |
| +class CoAPCommands(wsplugin.DemoPlugin): |
| + |
| + def get_commands(self): |
| + return ["coapled", "coaptemp"] |
| + |
| + def handle_command(self, wsdemo, cmds): |
| + if cmds[0] == "coapled": |
| + if coap_check(wsdemo): |
| + ip = cmds[1] |
| + led = cmds[2] |
| + on = cmds[3] |
| + thread.start_new_thread(coapled, (wsdemo, ip, led, on)) |
| + return True |
| + elif cmds[0] == "coaptemp": |
| + if coap_check(wsdemo): |
| + ip = cmds[1] |
| + thread.start_new_thread(coaptemp, (wsdemo, ip)) |
| + return True |
| + return False |
| + |
| +# Toggle a LED on a Yanzi IoT-U10 node (or other node with LEDs) |
| +def coapled(ws, ip, led, on): |
| + coap_put(ws, "coap://[" + ip + "]/led/" + led, on) |
| + |
| +# Read the temperature from a Yanzi IoT-U10 node |
| +def coaptemp(ws, ip): |
| + temperature = coap_get(ws, "coap://[" + ip + "]/temperature") |
| + print "\t",temperature |
| + # get the temperature from the coap response |
| + m = re.search("Temperature .+: (.+)", temperature) |
| + if m: |
| + ws.sendMessage(json.dumps({"temp":m.group(1),"address":ip})) |
| + else: |
| + ws.sendMessage(json.dumps({"error":"Failed to fetch temperature via CoAP"})) |
| diff --git a/examples/sparrow/wspnodes.py b/examples/sparrow/wspnodes.py |
| index 3f5dc13..abfd1ae 100644 |
| --- a/examples/sparrow/wspnodes.py |
| +++ b/examples/sparrow/wspnodes.py |
| @@ -28,6 +28,7 @@ |
| # |
| |
| import socket, binascii, wsplugin, tlvlib, thread, deviceserver, json, struct, urllib2, time |
| +import wspcoap |
| |
| RANK_DIVISOR = 128.0 |
| |
| @@ -102,37 +103,40 @@ class NodeCommands(wsplugin.DemoPlugin): |
| node = 2 |
| nodes[endfix] = 1 |
| for device in devs: |
| - rpl = device.nstats_rpl |
| - parent = None |
| + rpl = wspcoap.coap_get(ws, "coap://[" + device.address + "]/rpl-info") |
| if rpl is None: |
| rank = "unknown" |
| else: |
| - rank = rpl.dag_rank() / RANK_DIVISOR |
| - parent = rpl.parent_as_string() |
| + parent1 = rpl.split('\n', 4)[1] |
| + rank1 = rpl.split('\n', 4)[2] |
| + rank = rank1.split('-', 2)[1], |
| + parent = parent1.split('-', 2)[1] |
| addr = socket.inet_pton(socket.AF_INET6, device.address) |
| endfix = binascii.hexlify(addr[-4:]) |
| # First we add the parent as level - second round we will |
| # change this to "level" instead |
| - topology["nodes"] = topology["nodes"] + [{"id":node, "label":"N" + str(node), "title":"Rank " + str(rank) + "<br>" + device.address, |
| - "level":-1, "parent":parent, "address":endfix}] |
| + topology["nodes"] = topology["nodes"] + [{"id":node, "label":"N" + str(node), |
| + "title":"Rank " + str(rank) + "<br>" + device.address, |
| + "level":-1, "parent":str(parent), "address":endfix}] |
| nodes[endfix] = node |
| node = node + 1 |
| |
| - changed = True |
| - i = 0 |
| edges = [] |
| - while changed and i < 10: |
| - changed = False |
| + i = 0 |
| + while i < 3: |
| i = i + 1 |
| for n in topology["nodes"]: |
| if n["level"] is -1: |
| - p = topology["nodes"][nodes[n["parent"]] - 1] |
| - # add an edge |
| - edges = edges + [{"from":p["id"],"to":n["id"]}] |
| - if p["level"] is not -1: |
| - n["level"] = p["level"] + 1 |
| - #print "level should be ", p["level"] + 1 |
| - changed = True |
| + parent = socket.inet_pton(socket.AF_INET6, n["parent"]) |
| + endfix = binascii.hexlify(parent[-4:]) |
| + for k in topology["nodes"]: |
| + if k["address"] == endfix: |
| + # add an edge |
| + edges = edges + [{"from":k["id"],"to":n["id"]}] |
| + if k["level"] is not -1: |
| + n["level"] = k["level"] + 1 |
| + break |
| + |
| topology["edges"] = edges |
| print "Sending json: ",json.dumps({'topology':topology}) |
| ws.sendMessage(json.dumps({'topology':topology})) |
| diff --git a/examples/sparrow/www/index.html b/examples/sparrow/www/index.html |
| index 685fb64..631f597 100644 |
| --- a/examples/sparrow/www/index.html |
| +++ b/examples/sparrow/www/index.html |
| @@ -292,6 +292,9 @@ function getTypeButtons(type, address) { |
| '<button class="cupid-green-small" onClick="led_control(\'' + address + '\',1)">Led 2 Toggle</button> ' + |
| '<button class="cupid-green-small" onClick="led_control(\'' + address + '\',2)">Led 3 Toggle</button> ' + |
| '<button class="cupid-green-small" onClick="temp_read(\'' + address + '\')">Read Temp</button>'; |
| + } else { |
| + buttons = buttons + |
| + '<button class="cupid-green-small" onClick="coap_led_control(\'' + address + '\',0,1)">Led 1 On</button> <button class="cupid-green-small" onClick="coap_led_control(\'' + address + '\',0,0)">Led 1 Off</button>'; |
| } |
| return buttons; |
| } |
| @@ -305,6 +308,14 @@ function temp_read(address) { |
| doSend("tlvtemp " + address); |
| } |
| |
| +function coap_led_control(address, led, val) { |
| + doSend("coapled " + address + " " + led + " " + val); |
| +} |
| + |
| +function coap_temp_read(address) { |
| + doSend("coaptemp " + address); |
| +} |
| + |
| function handleEvent(json) { |
| if (json.event.type == "discovery") { |
| addr = json.event.address.replace(new RegExp(":", 'g'), "\\:"); |
| @@ -563,6 +574,7 @@ function updateRSSI(rssi) { |
| <li>Javascript-surface-plot by Greg Ross (New BSD License) |
| <li>Vis.js for Network Topology Graphs (Apache 2.0 and MIT License) |
| <li>SimpleWebSocketServer - Python library by Dave Pallot (MIT License) |
| + <li>libcoap - a CoAP library by Olaf Bergmann (BSD License) |
| </ul> |
| </div> |
| </div> |
| diff --git a/products/sparrow-border-router/project-conf.h b/products/sparrow-border-router/project-conf.h |
| index 0921f13..1a8f32e 100644 |
| --- a/products/sparrow-border-router/project-conf.h |
| +++ b/products/sparrow-border-router/project-conf.h |
| @@ -88,6 +88,8 @@ |
| #undef WEBSERVER_CONF_CFS_CONNS |
| #define WEBSERVER_CONF_CFS_CONNS 2 |
| |
| +#define WEBSERVER 1 |
| + |
| #define CMD_CONF_OUTPUT border_router_cmd_output |
| #define CMD_CONF_ERROR border_router_cmd_error |
| |
| @@ -100,6 +102,7 @@ |
| /* Configure DAO routes to have a lifetime of 30 x 60 seconds */ |
| #define RPL_CONF_DEFAULT_LIFETIME_UNIT 60 |
| #define RPL_CONF_DEFAULT_LIFETIME 30 |
| +#define RPL_CONF_WITH_DAO_ACK 1 |
| |
| #undef NBR_TABLE_CONF_MAX_NEIGHBORS |
| #define NBR_TABLE_CONF_MAX_NEIGHBORS 1000 |
| diff --git a/tools/sparrow/deviceserver.py b/tools/sparrow/deviceserver.py |
| index 754e872..3796ad5 100755 |
| --- a/tools/sparrow/deviceserver.py |
| +++ b/tools/sparrow/deviceserver.py |
| @@ -595,6 +595,7 @@ class DeviceServer: |
| |
| p = re.compile(" ([a-fA-F0-9:]+)(/| prefixlen )") |
| m = p.search(output) |
| + return default_host |
| if m: |
| return m.group(1) |
| else: |
| -- |
| 2.11.0 |
| |