273 lines
11 KiB
Diff
273 lines
11 KiB
Diff
|
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
|
||
|
|