blob: 9d2481c68fac91ede5778376b55e9b66483dba1a [file] [log] [blame]
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>&nbsp;' +
'<button class="cupid-green-small" onClick="led_control(\'' + address + '\',2)">Led 3 Toggle</button>&nbsp;' +
'<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>&nbsp;<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