From 55f4f2ab44bf6bf098b0b697d8ad30692794cd8f Mon Sep 17 00:00:00 2001 From: Yasuyuki Tanaka Date: Mon, 26 Mar 2018 20:51:02 +0200 Subject: [PATCH 001/129] tests/09-ipv6: add tests on neighbor cache update --- .travis.yml | 1 + tests/09-ipv6/01-ping-lla-csma-w-rpl.csc | 108 ++++++++++++++++++++++ tests/09-ipv6/02-ping-ula-csma-w-rpl.csc | 108 ++++++++++++++++++++++ tests/09-ipv6/03-ping-lla-tsch-w-rpl.csc | 108 ++++++++++++++++++++++ tests/09-ipv6/04-ping-ula-tsch-w-rpl.csc | 108 ++++++++++++++++++++++ tests/09-ipv6/05-ping-lla-csma-wo-rpl.csc | 108 ++++++++++++++++++++++ tests/09-ipv6/06-ping-ula-csma-wo-rpl.csc | 108 ++++++++++++++++++++++ tests/09-ipv6/07-ping-lla-tsch-wo-rpl.csc | 108 ++++++++++++++++++++++ tests/09-ipv6/08-ping-ula-tsch-wo-rpl.csc | 108 ++++++++++++++++++++++ tests/09-ipv6/Makefile | 1 + tests/09-ipv6/code/Makefile | 35 +++++++ tests/09-ipv6/code/node.c | 82 ++++++++++++++++ tests/09-ipv6/js/ping-test-lla.js | 45 +++++++++ tests/09-ipv6/js/ping-test-ula.js | 47 ++++++++++ 14 files changed, 1075 insertions(+) create mode 100644 tests/09-ipv6/01-ping-lla-csma-w-rpl.csc create mode 100644 tests/09-ipv6/02-ping-ula-csma-w-rpl.csc create mode 100644 tests/09-ipv6/03-ping-lla-tsch-w-rpl.csc create mode 100644 tests/09-ipv6/04-ping-ula-tsch-w-rpl.csc create mode 100644 tests/09-ipv6/05-ping-lla-csma-wo-rpl.csc create mode 100644 tests/09-ipv6/06-ping-ula-csma-wo-rpl.csc create mode 100644 tests/09-ipv6/07-ping-lla-tsch-wo-rpl.csc create mode 100644 tests/09-ipv6/08-ping-ula-tsch-wo-rpl.csc create mode 100644 tests/09-ipv6/Makefile create mode 100644 tests/09-ipv6/code/Makefile create mode 100644 tests/09-ipv6/code/node.c create mode 100644 tests/09-ipv6/js/ping-test-lla.js create mode 100644 tests/09-ipv6/js/ping-test-ula.js diff --git a/.travis.yml b/.travis.yml index 00dba89ab..0467424de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,3 +33,4 @@ env: - TEST_NAME='doxygen' - TEST_NAME='compile-tools' - TEST_NAME='native-runs' + - TEST_NAME='ipv6' diff --git a/tests/09-ipv6/01-ping-lla-csma-w-rpl.csc b/tests/09-ipv6/01-ping-lla-csma-w-rpl.csc new file mode 100644 index 000000000..0a6e3a376 --- /dev/null +++ b/tests/09-ipv6/01-ping-lla-csma-w-rpl.csc @@ -0,0 +1,108 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/powertracker + + My simulation + 1.0 + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype787 + Cooja Mote Type #1 + [CONTIKI_DIR]/tests/09-ipv6/code/node.c + make clean + make WITH_CSMA=1 node.cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + + org.contikios.cooja.interfaces.Position + 14.03051207883138 + 82.02801380504546 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + ip-nbr~;ping fe80::202:2:2:2~;ip-nbr~;help~;je;p~;ping da~;ping~;help~; + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.interfaces.Position + 28.22612889898729 + 43.60027658221718 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.plugins.ScriptRunner + + [CONTIKI_DIR]/tests/09-ipv6/js/ping-test-lla.js + true + + 495 + 0 + 525 + 190 + 18 + + diff --git a/tests/09-ipv6/02-ping-ula-csma-w-rpl.csc b/tests/09-ipv6/02-ping-ula-csma-w-rpl.csc new file mode 100644 index 000000000..802f068cc --- /dev/null +++ b/tests/09-ipv6/02-ping-ula-csma-w-rpl.csc @@ -0,0 +1,108 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/powertracker + + My simulation + 1.0 + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype787 + Cooja Mote Type #1 + [CONTIKI_DIR]/tests/09-ipv6/code/node.c + make clean + make WITH_ULA=1 WITH_CSMA=1 node.cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + + org.contikios.cooja.interfaces.Position + 14.03051207883138 + 82.02801380504546 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + ip-nbr~;ping fe80::202:2:2:2~;ip-nbr~;help~;je;p~;ping da~;ping~;help~; + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.interfaces.Position + 28.22612889898729 + 43.60027658221718 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.plugins.ScriptRunner + + [CONTIKI_DIR]/tests/09-ipv6/js/ping-test-ula.js + true + + 495 + 0 + 525 + 190 + 18 + + diff --git a/tests/09-ipv6/03-ping-lla-tsch-w-rpl.csc b/tests/09-ipv6/03-ping-lla-tsch-w-rpl.csc new file mode 100644 index 000000000..2642f363d --- /dev/null +++ b/tests/09-ipv6/03-ping-lla-tsch-w-rpl.csc @@ -0,0 +1,108 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/powertracker + + My simulation + 1.0 + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype787 + Cooja Mote Type #1 + [CONTIKI_DIR]/tests/09-ipv6/code/node.c + make clean + make WITH_TSCH=1 node.cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + + org.contikios.cooja.interfaces.Position + 14.03051207883138 + 82.02801380504546 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + ip-nbr~;ping fe80::202:2:2:2~;ip-nbr~;help~;je;p~;ping da~;ping~;help~; + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.interfaces.Position + 28.22612889898729 + 43.60027658221718 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.plugins.ScriptRunner + + [CONTIKI_DIR]/tests/09-ipv6/js/ping-test-lla.js + true + + 495 + 0 + 525 + 190 + 18 + + diff --git a/tests/09-ipv6/04-ping-ula-tsch-w-rpl.csc b/tests/09-ipv6/04-ping-ula-tsch-w-rpl.csc new file mode 100644 index 000000000..c18f8ac0b --- /dev/null +++ b/tests/09-ipv6/04-ping-ula-tsch-w-rpl.csc @@ -0,0 +1,108 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/powertracker + + My simulation + 1.0 + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype787 + Cooja Mote Type #1 + [CONTIKI_DIR]/tests/09-ipv6/code/node.c + make clean + make WITH_ULA=1 WITH_TSCH=1 node.cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + + org.contikios.cooja.interfaces.Position + 14.03051207883138 + 82.02801380504546 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + ip-nbr~;ping fe80::202:2:2:2~;ip-nbr~;help~;je;p~;ping da~;ping~;help~; + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.interfaces.Position + 28.22612889898729 + 43.60027658221718 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.plugins.ScriptRunner + + [CONTIKI_DIR]/tests/09-ipv6/js/ping-test-ula.js + true + + 495 + 0 + 525 + 190 + 18 + + diff --git a/tests/09-ipv6/05-ping-lla-csma-wo-rpl.csc b/tests/09-ipv6/05-ping-lla-csma-wo-rpl.csc new file mode 100644 index 000000000..9b3d1c50f --- /dev/null +++ b/tests/09-ipv6/05-ping-lla-csma-wo-rpl.csc @@ -0,0 +1,108 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/powertracker + + My simulation + 1.0 + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype787 + Cooja Mote Type #1 + [CONTIKI_DIR]/tests/09-ipv6/code/node.c + make clean + make WITH_CSMA=1 WITHOUT_RPL=1 node.cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + + org.contikios.cooja.interfaces.Position + 14.03051207883138 + 82.02801380504546 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + ip-nbr~;ping fe80::202:2:2:2~;ip-nbr~;help~;je;p~;ping da~;ping~;help~; + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.interfaces.Position + 28.22612889898729 + 43.60027658221718 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.plugins.ScriptRunner + + [CONTIKI_DIR]/tests/09-ipv6/js/ping-test-lla.js + true + + 495 + 0 + 525 + 190 + 18 + + diff --git a/tests/09-ipv6/06-ping-ula-csma-wo-rpl.csc b/tests/09-ipv6/06-ping-ula-csma-wo-rpl.csc new file mode 100644 index 000000000..3640cbb1f --- /dev/null +++ b/tests/09-ipv6/06-ping-ula-csma-wo-rpl.csc @@ -0,0 +1,108 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/powertracker + + My simulation + 1.0 + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype787 + Cooja Mote Type #1 + [CONTIKI_DIR]/tests/09-ipv6/code/node.c + make clean + make WITH_ULA=1 WITH_CSMA=1 WITHOUT_RPL=1 node.cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + + org.contikios.cooja.interfaces.Position + 14.03051207883138 + 82.02801380504546 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + ip-nbr~;ping fe80::202:2:2:2~;ip-nbr~;help~;je;p~;ping da~;ping~;help~; + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.interfaces.Position + 28.22612889898729 + 43.60027658221718 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.plugins.ScriptRunner + + [CONTIKI_DIR]/tests/09-ipv6/js/ping-test-ula.js + true + + 495 + 0 + 525 + 190 + 18 + + diff --git a/tests/09-ipv6/07-ping-lla-tsch-wo-rpl.csc b/tests/09-ipv6/07-ping-lla-tsch-wo-rpl.csc new file mode 100644 index 000000000..2960bacaf --- /dev/null +++ b/tests/09-ipv6/07-ping-lla-tsch-wo-rpl.csc @@ -0,0 +1,108 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/powertracker + + My simulation + 1.0 + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype787 + Cooja Mote Type #1 + [CONTIKI_DIR]/tests/09-ipv6/code/node.c + make clean + make WITH_TSCH=1 WITHOUT_RPL=1 node.cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + + org.contikios.cooja.interfaces.Position + 14.03051207883138 + 82.02801380504546 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + ip-nbr~;ping fe80::202:2:2:2~;ip-nbr~;help~;je;p~;ping da~;ping~;help~; + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.interfaces.Position + 28.22612889898729 + 43.60027658221718 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.plugins.ScriptRunner + + [CONTIKI_DIR]/tests/09-ipv6/js/ping-test-lla.js + true + + 495 + 0 + 525 + 190 + 18 + + diff --git a/tests/09-ipv6/08-ping-ula-tsch-wo-rpl.csc b/tests/09-ipv6/08-ping-ula-tsch-wo-rpl.csc new file mode 100644 index 000000000..73953b0b3 --- /dev/null +++ b/tests/09-ipv6/08-ping-ula-tsch-wo-rpl.csc @@ -0,0 +1,108 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/powertracker + + My simulation + 1.0 + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype787 + Cooja Mote Type #1 + [CONTIKI_DIR]/tests/09-ipv6/code/node.c + make clean + make WITH_ULA=1 WITH_TSCH=1 WITHOUT_RPL=1 node.cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + + org.contikios.cooja.interfaces.Position + 14.03051207883138 + 82.02801380504546 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + ip-nbr~;ping fe80::202:2:2:2~;ip-nbr~;help~;je;p~;ping da~;ping~;help~; + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.interfaces.Position + 28.22612889898729 + 43.60027658221718 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiEEPROM + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + mtype787 + + + + org.contikios.cooja.plugins.ScriptRunner + + [CONTIKI_DIR]/tests/09-ipv6/js/ping-test-ula.js + true + + 495 + 0 + 525 + 190 + 18 + + diff --git a/tests/09-ipv6/Makefile b/tests/09-ipv6/Makefile new file mode 100644 index 000000000..272bc7da1 --- /dev/null +++ b/tests/09-ipv6/Makefile @@ -0,0 +1 @@ +include ../Makefile.simulation-test diff --git a/tests/09-ipv6/code/Makefile b/tests/09-ipv6/code/Makefile new file mode 100644 index 000000000..2c910f1cd --- /dev/null +++ b/tests/09-ipv6/code/Makefile @@ -0,0 +1,35 @@ +CONTIKI_PRJECT = node +all: $(CONTIKI_PROJECT) + +MODULES += os/services/shell +CFLAGS += -DLOG_CONF_LEVEL_RPL=LOG_LEVEL_INFO +CFLAGS += -DLOG_CONF_LEVEL_TCPIP=LOG_LEVEL_INFO +CFLAGS += -DLOG_CONF_LEVEL_IPV6=LOG_LEVEL_DBG +CFLAGS += -DLOG_CONF_LEVEL_MAC=LOG_LEVEL_INFO + +ifeq ($(WITH_ULA),1) + CFLAGS += -DWITH_ULA=1 +endif + +ifeq ($(WITHOUT_RPL),1) + MAKE_ROUTING = MAKE_ROUTING_NULLROUTING +else + CFLAGS += -DRPL_CONF_DAO_DELAY=1 +endif + +ifeq ($WITH_CSMA),1) + MAKE_MAC = MAKE_MAC_CSMA +endif + +ifeq ($(WITH_TSCH),1) + MAKE_MAC = MAKE_MAC_TSCH + CFLAGS += -DWITH_TSCH=1 + CFLAGS += -DTSCH_CONF_AUTOSTART=1 + CFLAGS += -DTSCH_CONF_DEFAULT_HOPPING_SEQUENCE=TSCH_HOPPING_SEQUENCE_1_1 +endif + +PLATFORM_ONLY = cooja +TARGET = cooja + +CONTIKI = ../../../ +include $(CONTIKI)/Makefile.include diff --git a/tests/09-ipv6/code/node.c b/tests/09-ipv6/code/node.c new file mode 100644 index 000000000..f465e2642 --- /dev/null +++ b/tests/09-ipv6/code/node.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016, Yasuyuki Tanaka + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include + +PROCESS(node_process, "Node"); +AUTOSTART_PROCESSES(&node_process); + +PROCESS_THREAD(node_process, ev, data) +{ + static struct etimer et; +#if WITH_ULA + static uip_ipaddr_t ipaddr; +#endif /* WITH_ULA */ + +#if WITH_TSCH + static linkaddr_t coordinator_addr = {{0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01}}; +#endif /* WITH_TSCH */ + + PROCESS_BEGIN(); + +#if WITH_TSCH + if(linkaddr_cmp(&coordinator_addr, &linkaddr_node_addr)) { + tsch_set_coordinator(1); + } +#endif /* WITH_TSCH */ + +#if WITH_ULA + uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0); + uip_ds6_prefix_add(&ipaddr, UIP_DEFAULT_PREFIX_LEN, 0, 0, 0, 0); + uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); + uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); +#endif /* WITH_ULA */ + + serial_shell_init(); + + etimer_set(&et, CLOCK_SECOND); + while(1) { + /* + * keep doing something so that simulation runs until its timeout + */ + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); + printf(".\n"); + etimer_reset(&et); + } + + PROCESS_END(); +} diff --git a/tests/09-ipv6/js/ping-test-lla.js b/tests/09-ipv6/js/ping-test-lla.js new file mode 100644 index 000000000..1823d87b2 --- /dev/null +++ b/tests/09-ipv6/js/ping-test-lla.js @@ -0,0 +1,45 @@ +TIMEOUT(20000, log.testFailed()); + +dst_lla = "fe80::202:2:2:2"; +dst_mac = "0002.0002.0002.0002"; +step = 0; + +while(1) { + YIELD(); + log.log(time + " " + id + " "+ msg + "\n"); + + if(msg.contains("Node id is set to")) { + if(id == 1) { + write(sim.getMoteWithID(1), "rpl-set-root 1"); + } + step += 1; + } + + if(step == 2 && time > 15000000) { + write(sim.getMoteWithID(1), "ping " + dst_lla); + step += 1; + } + + if(msg.contains("Received ping reply")) { + write(sim.getMoteWithID(1), "ip-nbr"); + } + + if(msg.contains("<->")) { + re = /-- | <-> |, router|, state /; + nc = msg.split(re); + ip_addr = nc[1]; + ll_addr = nc[2]; + is_router = nc[3]; + state = nc[4].trim(); + if(ip_addr == dst_lla && + ll_addr == dst_mac && + state == "Reachable") { + log.testOK(); + } else { + log.log(ip_addr + "\n"); + log.log(ll_addr + "\n"); + log.log(state + "\n"); + log.testFailed(); + } + } +} diff --git a/tests/09-ipv6/js/ping-test-ula.js b/tests/09-ipv6/js/ping-test-ula.js new file mode 100644 index 000000000..b78f0342a --- /dev/null +++ b/tests/09-ipv6/js/ping-test-ula.js @@ -0,0 +1,47 @@ +;TIMEOUT(20000, log.testFailed()); + +dst_lla = "fe80::202:2:2:2"; +dst_ula = "fd00::202:2:2:2"; +dst_mac = "0002.0002.0002.0002"; +step = 0; + +while(1) { + YIELD(); + log.log(time + " " + id + " "+ msg + "\n"); + + if(msg.contains("Node id is set to")) { + if(id == 1) { + write(sim.getMoteWithID(1), "rpl-set-root 1"); + } + step += 1; + } + + if(step == 2 && time > 15000000) { + write(sim.getMoteWithID(1), "ping " + dst_ula); + step += 1; + } + + if(msg.contains("Received ping reply")) { + write(sim.getMoteWithID(1), "ip-nbr"); + } + + if(msg.contains("<->")) { + re = /-- | <-> |, router|, state /; + nc = msg.split(re); + ip_addr = nc[1]; + ll_addr = nc[2]; + is_router = nc[3]; + state = nc[4].trim(); + /* in RPL case, nbr doesn't have ula. */ + if((ip_addr == dst_lla || ip_addr == dst_ula) && + ll_addr == dst_mac && + state == "Reachable") { + log.testOK(); + } else { + log.log(ip_addr + "\n"); + log.log(ll_addr + "\n"); + log.log(state + "\n"); + log.testFailed(); + } + } +} From 601e14ebc7b588489e271c284b8993ada5cf0504 Mon Sep 17 00:00:00 2001 From: Yasuyuki Tanaka Date: Fri, 23 Mar 2018 13:51:27 +0000 Subject: [PATCH 002/129] uip-nd6: bugfix on address resolution by Neighbor Discovery protocol nbr_table_update_lladdr() fails to update the lladdr of a nbr with a new one when the new lladdr is used in nbr_table. This causes communication errors when NS/NA is employed. uip_ds6_nbr_update_ll() is introduced to resolve this issue. And nbr_table_update_lladdr() is removed since it's not used any more. --- os/net/ipv6/uip-ds6-nbr.c | 35 +++++++++++++++++++++++++++++++++++ os/net/ipv6/uip-ds6-nbr.h | 1 + os/net/ipv6/uip-nd6.c | 14 ++++++++++---- os/net/nbr-table.c | 33 --------------------------------- os/net/nbr-table.h | 1 - 5 files changed, 46 insertions(+), 38 deletions(-) diff --git a/os/net/ipv6/uip-ds6-nbr.c b/os/net/ipv6/uip-ds6-nbr.c index e49125548..f937986b5 100644 --- a/os/net/ipv6/uip-ds6-nbr.c +++ b/os/net/ipv6/uip-ds6-nbr.c @@ -127,6 +127,41 @@ uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr) return 0; } +/*---------------------------------------------------------------------------*/ +int +uip_ds6_nbr_update_ll(uip_ds6_nbr_t **nbr_pp, const uip_lladdr_t *new_ll_addr) +{ + uip_ds6_nbr_t nbr_backup; + + if(nbr_pp == NULL || new_ll_addr == NULL) { + LOG_ERR("%s: invalid argument\n", __func__); + return -1; + } + + /* make sure new_ll_addr is not used in some other nbr */ + if(uip_ds6_nbr_ll_lookup(new_ll_addr) != NULL) { + LOG_ERR("%s: new_ll_addr, ", __func__); + LOG_ERR_LLADDR((const linkaddr_t *)new_ll_addr); + LOG_ERR_(", is already used in another nbr\n"); + return -1; + } + + memcpy(&nbr_backup, *nbr_pp, sizeof(uip_ds6_nbr_t)); + if(uip_ds6_nbr_rm(*nbr_pp) == 0) { + LOG_ERR("%s: input nbr cannot be removed\n", __func__); + return -1; + } + + if((*nbr_pp = uip_ds6_nbr_add(&nbr_backup.ipaddr, new_ll_addr, + nbr_backup.isrouter, nbr_backup.state, + NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) { + LOG_ERR("%s: cannot allocate a new nbr for new_ll_addr\n", __func__); + return -1; + } + memcpy(*nbr_pp, &nbr_backup, sizeof(uip_ds6_nbr_t)); + + return 0; +} /*---------------------------------------------------------------------------*/ const uip_ipaddr_t * uip_ds6_nbr_get_ipaddr(const uip_ds6_nbr_t *nbr) diff --git a/os/net/ipv6/uip-ds6-nbr.h b/os/net/ipv6/uip-ds6-nbr.h index 9aec47b4a..d645ac627 100644 --- a/os/net/ipv6/uip-ds6-nbr.h +++ b/os/net/ipv6/uip-ds6-nbr.h @@ -90,6 +90,7 @@ uip_ds6_nbr_t *uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, nbr_table_reason_t reason, void *data); int uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr); const uip_lladdr_t *uip_ds6_nbr_get_ll(const uip_ds6_nbr_t *nbr); +int uip_ds6_nbr_update_ll(uip_ds6_nbr_t **nbr, const uip_lladdr_t *new_ll_addr); const uip_ipaddr_t *uip_ds6_nbr_get_ipaddr(const uip_ds6_nbr_t *nbr); uip_ds6_nbr_t *uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr); uip_ds6_nbr_t *uip_ds6_nbr_ll_lookup(const uip_lladdr_t *lladdr); diff --git a/os/net/ipv6/uip-nd6.c b/os/net/ipv6/uip-nd6.c index ce555ed53..7a5724308 100644 --- a/os/net/ipv6/uip-nd6.c +++ b/os/net/ipv6/uip-nd6.c @@ -230,7 +230,9 @@ ns_input(void) } if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, UIP_LLADDR_LEN) != 0) { - if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) { + if(uip_ds6_nbr_update_ll(&nbr, + (const uip_lladdr_t *)&lladdr_aligned) + < 0) { /* failed to update the lladdr */ goto discard; } @@ -534,7 +536,8 @@ na_input(void) if(nd6_opt_llao == NULL || !extract_lladdr_from_llao_aligned(&lladdr_aligned)) { goto discard; } - if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) { + if(uip_ds6_nbr_update_ll(&nbr, + (const uip_lladdr_t *)&lladdr_aligned) < 0) { /* failed to update the lladdr */ goto discard; } @@ -561,7 +564,9 @@ na_input(void) if(is_override || !is_llchange || nd6_opt_llao == NULL) { if(nd6_opt_llao != NULL && is_llchange) { if(!extract_lladdr_from_llao_aligned(&lladdr_aligned) || - nbr_table_update_lladdr((const linkaddr_t *) lladdr, (const linkaddr_t *) &lladdr_aligned, 1) == 0) { + uip_ds6_nbr_update_ll(&nbr, + (const uip_lladdr_t *)&lladdr_aligned) + < 0) { /* failed to update the lladdr */ goto discard; } @@ -925,7 +930,8 @@ ra_input(void) if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, UIP_LLADDR_LEN) != 0) { /* change of link layer address */ - if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) { + if(uip_ds6_nbr_update_ll(&nbr, + (const uip_lladdr_t *)&lladdr_aligned) < 0) { /* failed to update the lladdr */ goto discard; } diff --git a/os/net/nbr-table.c b/os/net/nbr-table.c index 77d3cb07d..8a8eaeb78 100644 --- a/os/net/nbr-table.c +++ b/os/net/nbr-table.c @@ -439,39 +439,6 @@ nbr_table_get_lladdr(nbr_table_t *table, const void *item) return key != NULL ? &key->lladdr : NULL; } /*---------------------------------------------------------------------------*/ -/* Update link-layer address of an item */ -int -nbr_table_update_lladdr(const linkaddr_t *old_addr, const linkaddr_t *new_addr, - int remove_if_duplicate) -{ - int index; - int new_index; - nbr_table_key_t *key; - index = index_from_lladdr(old_addr); - if(index == -1) { - /* Failure to change since there is nothing to change. */ - return 0; - } - if((new_index = index_from_lladdr(new_addr)) != -1) { - /* check if it is a change or not - do not remove / fail if same */ - if(new_index == index) { - return 1; - } - /* This new entry already exists - failure! - remove if requested. */ - if(remove_if_duplicate) { - remove_key(key_from_index(index)); - } - return 0; - } - key = key_from_index(index); - /** - * Copy the new lladdr into the key - since we know that there is no - * conflicting entry. - */ - memcpy(&key->lladdr, new_addr, sizeof(linkaddr_t)); - return 1; -} -/*---------------------------------------------------------------------------*/ #if DEBUG static void print_table() diff --git a/os/net/nbr-table.h b/os/net/nbr-table.h index d7fad5267..0dccd1092 100644 --- a/os/net/nbr-table.h +++ b/os/net/nbr-table.h @@ -113,7 +113,6 @@ int nbr_table_unlock(nbr_table_t *table, nbr_table_item_t *item); /** \name Neighbor tables: address manipulation */ /** @{ */ linkaddr_t *nbr_table_get_lladdr(nbr_table_t *table, const nbr_table_item_t *item); -int nbr_table_update_lladdr(const linkaddr_t *old_addr, const linkaddr_t *new_addr, int remove_if_duplicate); /** @} */ #endif /* NBR_TABLE_H_ */ From 4ededd17d60f2e4eef0260771855643455c7b851 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 31 Mar 2018 22:20:24 +0100 Subject: [PATCH 003/129] Emulate interrupt manipulation on native --- arch/cpu/native/Makefile.native | 2 +- arch/cpu/native/int-master.c | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 arch/cpu/native/int-master.c diff --git a/arch/cpu/native/Makefile.native b/arch/cpu/native/Makefile.native index 90a784e34..4e0558a2f 100644 --- a/arch/cpu/native/Makefile.native +++ b/arch/cpu/native/Makefile.native @@ -1,6 +1,6 @@ CONTIKI_CPU_DIRS = . net dev -CONTIKI_SOURCEFILES += rtimer-arch.c watchdog.c eeprom.c +CONTIKI_SOURCEFILES += rtimer-arch.c watchdog.c eeprom.c int-master.c ### Compiler definitions CC ?= gcc diff --git a/arch/cpu/native/int-master.c b/arch/cpu/native/int-master.c new file mode 100644 index 000000000..177dbd442 --- /dev/null +++ b/arch/cpu/native/int-master.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018, George Oikonomou - http://www.spd.gr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "sys/int-master.h" + +#include +/*---------------------------------------------------------------------------*/ +#define DISABLED 0 +#define ENABLED 1 +/*---------------------------------------------------------------------------*/ +static int_master_status_t stat = DISABLED; +/*---------------------------------------------------------------------------*/ +void +int_master_enable(void) +{ + stat = ENABLED; +} +/*---------------------------------------------------------------------------*/ +int_master_status_t +int_master_read_and_disable(void) +{ + int_master_status_t rv = stat; + stat = DISABLED; + return rv; +} +/*---------------------------------------------------------------------------*/ +void +int_master_status_set(int_master_status_t status) +{ + stat = status; +} +/*---------------------------------------------------------------------------*/ +bool +int_master_is_enabled(void) +{ + return stat == DISABLED ? false : true; +} +/*---------------------------------------------------------------------------*/ From b8a43e8bf9578e2428c7dc8b94fc30cd82c0a90f Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 30 Mar 2018 19:59:14 +0100 Subject: [PATCH 004/129] Implement the button HAL for platform native --- arch/platform/native/Makefile.native | 2 +- arch/platform/native/contiki-conf.h | 2 ++ arch/platform/native/dev/buttons.c | 40 ++++++++++++++++++++++++++++ arch/platform/native/platform.c | 2 ++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 arch/platform/native/dev/buttons.c diff --git a/arch/platform/native/Makefile.native b/arch/platform/native/Makefile.native index bee104a6c..86d2c1b7a 100644 --- a/arch/platform/native/Makefile.native +++ b/arch/platform/native/Makefile.native @@ -10,7 +10,7 @@ CONTIKI_TARGET_DIRS = . dev CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} CONTIKI_TARGET_SOURCEFILES += platform.c clock.c xmem.c leds-arch.c -CONTIKI_TARGET_SOURCEFILES += cfs-posix.c cfs-posix-dir.c +CONTIKI_TARGET_SOURCEFILES += cfs-posix.c cfs-posix-dir.c buttons.c ifeq ($(HOST_OS),Windows) CONTIKI_TARGET_SOURCEFILES += wpcap-drv.c wpcap.c diff --git a/arch/platform/native/contiki-conf.h b/arch/platform/native/contiki-conf.h index ea1383660..7b809bfc7 100644 --- a/arch/platform/native/contiki-conf.h +++ b/arch/platform/native/contiki-conf.h @@ -91,6 +91,8 @@ typedef unsigned long clock_time_t; #define LOG_CONF_ENABLED 1 +#define PLATFORM_SUPPORTS_BUTTON_HAL 1 + /* Not part of C99 but actually present */ int strcasecmp(const char*, const char*); diff --git a/arch/platform/native/dev/buttons.c b/arch/platform/native/dev/buttons.c new file mode 100644 index 000000000..359f7a409 --- /dev/null +++ b/arch/platform/native/dev/buttons.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, George Oikonomou - http://www.spd.gr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "dev/button-hal.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +button_hal_button_t *button_hal_buttons[] = { NULL }; +const uint8_t button_hal_button_count = 0; +/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/native/platform.c b/arch/platform/native/platform.c index fceab0207..70687e303 100644 --- a/arch/platform/native/platform.c +++ b/arch/platform/native/platform.c @@ -56,6 +56,7 @@ #include "net/netstack.h" #include "dev/serial-line.h" +#include "dev/button-hal.h" #include "net/ipv6/uip.h" #include "net/ipv6/uip-debug.h" @@ -251,6 +252,7 @@ platform_process_args(int argc, char**argv) void platform_init_stage_one() { + button_hal_init(); return; } /*---------------------------------------------------------------------------*/ From 6857d2fe20583f52585fcb2e7c55e9e5f3c58ecd Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 31 Mar 2018 21:55:58 +0100 Subject: [PATCH 005/129] Implement the GPIO HAL for platform native --- arch/cpu/native/Makefile.native | 1 + arch/cpu/native/dev/gpio-hal-arch.c | 216 ++++++++++++++++++++++++++++ arch/cpu/native/native-def.h | 38 +++++ arch/platform/native/contiki-conf.h | 4 +- arch/platform/native/platform.c | 2 + 5 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 arch/cpu/native/dev/gpio-hal-arch.c create mode 100644 arch/cpu/native/native-def.h diff --git a/arch/cpu/native/Makefile.native b/arch/cpu/native/Makefile.native index 4e0558a2f..123f044c8 100644 --- a/arch/cpu/native/Makefile.native +++ b/arch/cpu/native/Makefile.native @@ -1,6 +1,7 @@ CONTIKI_CPU_DIRS = . net dev CONTIKI_SOURCEFILES += rtimer-arch.c watchdog.c eeprom.c int-master.c +CONTIKI_SOURCEFILES += gpio-hal-arch.c ### Compiler definitions CC ?= gcc diff --git a/arch/cpu/native/dev/gpio-hal-arch.c b/arch/cpu/native/dev/gpio-hal-arch.c new file mode 100644 index 000000000..553a23444 --- /dev/null +++ b/arch/cpu/native/dev/gpio-hal-arch.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2018, George Oikonomou - http://www.spd.gr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "dev/gpio-hal.h" +#include "sys/log.h" + +#include +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#define LOG_MODULE "GPIO arch" +#define LOG_LEVEL LOG_LEVEL_NONE +/*---------------------------------------------------------------------------*/ +static gpio_hal_pin_cfg_t pin_cfg[GPIO_HAL_PIN_COUNT]; +static uint8_t pin_state[GPIO_HAL_PIN_COUNT]; +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + LOG_DBG("Pin %u: Enabled interrupt\n", pin); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_interrupt_disable(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + LOG_DBG("Pin %u: Disabled interrupt\n", pin); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + pin_cfg[pin] = cfg; + LOG_DBG("Pin %u: Set config=0x%02x\n", pin, pin_cfg[pin]); +} +/*---------------------------------------------------------------------------*/ +gpio_hal_pin_cfg_t +gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return 0; + } + + LOG_DBG("Pin %u: Config=0x%02x\n", pin, pin_cfg[pin]); + return pin_cfg[pin]; +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_pin_set_input(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + LOG_DBG("Pin %u: Set input\n", pin); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_pin_set_output(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + LOG_DBG("Pin %u: Set output\n", pin); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_set_pin(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + pin_state[pin] = 1; + LOG_DBG("Pin %u: Set\n", pin); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_clear_pin(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + pin_state[pin] = 0; + LOG_DBG("Pin %u: Clear\n", pin); +} +/*---------------------------------------------------------------------------*/ +uint8_t +gpio_hal_arch_read_pin(gpio_hal_pin_t pin) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return 0; + } + + LOG_DBG("Pin %u: Read=%u\n", pin, pin_state[pin]); + return pin_state[pin]; +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_write_pin(gpio_hal_pin_t pin, uint8_t value) +{ + if(pin >= GPIO_HAL_PIN_COUNT) { + LOG_ERR("Pin %u out of bounds\n", pin); + return; + } + + pin_state[pin] = value; + LOG_DBG("Pin %u: Write=%u\n", pin, pin_state[pin]); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_set_pins(gpio_hal_pin_mask_t pins) +{ + gpio_hal_pin_t pin; + + for(pin = 0; pin < GPIO_HAL_PIN_COUNT; pin++) { + if(pins & (1 << pin)) { + pin_state[pin] = 1; + } + } + + LOG_DBG("Set pins 0x%08" PRIx32 "\n", pins); +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_clear_pins(gpio_hal_pin_mask_t pins) +{ + gpio_hal_pin_t pin; + + for(pin = 0; pin < GPIO_HAL_PIN_COUNT; pin++) { + if(pins & (1 << pin)) { + pin_state[pin] = 0; + } + } + + LOG_DBG("Clear pins 0x%08" PRIx32 "\n", pins); +} +/*---------------------------------------------------------------------------*/ +gpio_hal_pin_mask_t +gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins) +{ + gpio_hal_pin_t pin; + gpio_hal_pin_mask_t state = 0; + + for(pin = 0; pin < GPIO_HAL_PIN_COUNT; pin++) { + state |= (pin_state[pin] << pin); + } + + LOG_DBG("Read pins 0x%08" PRIx32 "\n", state); + return state; +} +/*---------------------------------------------------------------------------*/ +void +gpio_hal_arch_write_pins(gpio_hal_pin_mask_t pins, gpio_hal_pin_mask_t value) +{ + gpio_hal_pin_t pin; + + for(pin = 0; pin < GPIO_HAL_PIN_COUNT; pin++) { + if(pins & (1 << pin)) { + pin_state[pin] = (value & (1 << pin)) == 0 ? 0 : 1; + } + } + + LOG_DBG("Write pins 0x%08" PRIx32 "->0x%08" PRIx32 "\n", pins, value); +} +/*---------------------------------------------------------------------------*/ diff --git a/arch/cpu/native/native-def.h b/arch/cpu/native/native-def.h new file mode 100644 index 000000000..d85ae7100 --- /dev/null +++ b/arch/cpu/native/native-def.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, George Oikonomou - http://www.spd.gr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +#ifndef NATIVE_DEF_H_ +#define NATIVE_DEF_H_ +/*---------------------------------------------------------------------------*/ +#define GPIO_HAL_CONF_ARCH_SW_TOGGLE 1 +/*---------------------------------------------------------------------------*/ +#endif /* NATIVE_DEF_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/native/contiki-conf.h b/arch/platform/native/contiki-conf.h index 7b809bfc7..fd34cdbcd 100644 --- a/arch/platform/native/contiki-conf.h +++ b/arch/platform/native/contiki-conf.h @@ -37,7 +37,9 @@ #ifdef PROJECT_CONF_PATH #include PROJECT_CONF_PATH #endif /* PROJECT_CONF_PATH */ - +/*---------------------------------------------------------------------------*/ +#include "native-def.h" +/*---------------------------------------------------------------------------*/ #include #ifndef WIN32_LEAN_AND_MEAN #include diff --git a/arch/platform/native/platform.c b/arch/platform/native/platform.c index 70687e303..9b00f9fbd 100644 --- a/arch/platform/native/platform.c +++ b/arch/platform/native/platform.c @@ -57,6 +57,7 @@ #include "dev/serial-line.h" #include "dev/button-hal.h" +#include "dev/gpio-hal.h" #include "net/ipv6/uip.h" #include "net/ipv6/uip-debug.h" @@ -252,6 +253,7 @@ platform_process_args(int argc, char**argv) void platform_init_stage_one() { + gpio_hal_init(); button_hal_init(); return; } From 7872da3c9befba175f96bb24f77c2440e52b94fe Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 31 Mar 2018 23:24:16 +0100 Subject: [PATCH 006/129] Transition platform native to the new LED HAL --- arch/platform/native/Makefile.native | 2 +- arch/platform/native/contiki-conf.h | 2 - arch/platform/native/dev/leds-arch.c | 60 ---------------------------- arch/platform/native/platform.c | 2 + 4 files changed, 3 insertions(+), 63 deletions(-) delete mode 100644 arch/platform/native/dev/leds-arch.c diff --git a/arch/platform/native/Makefile.native b/arch/platform/native/Makefile.native index 86d2c1b7a..09c77b004 100644 --- a/arch/platform/native/Makefile.native +++ b/arch/platform/native/Makefile.native @@ -9,7 +9,7 @@ endif CONTIKI_TARGET_DIRS = . dev CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} -CONTIKI_TARGET_SOURCEFILES += platform.c clock.c xmem.c leds-arch.c +CONTIKI_TARGET_SOURCEFILES += platform.c clock.c xmem.c CONTIKI_TARGET_SOURCEFILES += cfs-posix.c cfs-posix-dir.c buttons.c ifeq ($(HOST_OS),Windows) diff --git a/arch/platform/native/contiki-conf.h b/arch/platform/native/contiki-conf.h index fd34cdbcd..8d2c13820 100644 --- a/arch/platform/native/contiki-conf.h +++ b/arch/platform/native/contiki-conf.h @@ -62,8 +62,6 @@ int select_set_callback(int fd, const struct select_callback *callback); typedef unsigned int uip_stats_t; -#define LEDS_CONF_LEGACY_API 1 - #ifndef UIP_CONF_BYTE_ORDER #define UIP_CONF_BYTE_ORDER UIP_LITTLE_ENDIAN #endif diff --git a/arch/platform/native/dev/leds-arch.c b/arch/platform/native/dev/leds-arch.c deleted file mode 100644 index 07addc84e..000000000 --- a/arch/platform/native/dev/leds-arch.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2005, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * This file is part of the Contiki operating system. - * - */ - -/** - * \file - * A brief description of what this file is. - * \author - * Adam Dunkels - */ - -#include "dev/leds.h" -static leds_mask_t leds; -/*---------------------------------------------------------------------------*/ -void -leds_arch_init(void) -{ - leds = 0; -} -/*---------------------------------------------------------------------------*/ -leds_mask_t -leds_arch_get(void) -{ - return leds; -} -/*---------------------------------------------------------------------------*/ -void -leds_arch_set(leds_mask_t l) -{ - leds = l; -} -/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/native/platform.c b/arch/platform/native/platform.c index 9b00f9fbd..c5c4f23e7 100644 --- a/arch/platform/native/platform.c +++ b/arch/platform/native/platform.c @@ -58,6 +58,7 @@ #include "dev/serial-line.h" #include "dev/button-hal.h" #include "dev/gpio-hal.h" +#include "dev/leds.h" #include "net/ipv6/uip.h" #include "net/ipv6/uip-debug.h" @@ -255,6 +256,7 @@ platform_init_stage_one() { gpio_hal_init(); button_hal_init(); + leds_init(); return; } /*---------------------------------------------------------------------------*/ From 024586c21aabe9412e26ed8438f5d45ee3e112d0 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 30 Mar 2018 16:16:55 +0100 Subject: [PATCH 007/129] Allow the MQTT client example for platform native --- examples/mqtt-client/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mqtt-client/Makefile b/examples/mqtt-client/Makefile index c4741bec9..d315cfea3 100644 --- a/examples/mqtt-client/Makefile +++ b/examples/mqtt-client/Makefile @@ -8,6 +8,6 @@ CONTIKI = ../.. MODULES_REL += arch/platform/$(TARGET) -PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul +PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul native include $(CONTIKI)/Makefile.include From 5e85d806252bd3aff0f7e0173cec98829168df21 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 30 Mar 2018 22:32:02 +0100 Subject: [PATCH 008/129] Test the MQTT client for platform native --- tests/01-compile-base/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index 0c7e248e0..17ee36bf4 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -22,6 +22,7 @@ rpl-border-router/sky \ slip-radio/sky \ ipv6-hooks/sky \ nullnet/native \ +mqtt-client/native \ TOOLS= From 908641f32401c6a43d845f91c510c54258e5b42b Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 1 Apr 2018 15:37:09 +0100 Subject: [PATCH 009/129] Use correct format specifier for gpio_hal_pin_mask_t --- examples/dev/gpio-hal/gpio-hal-example.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/dev/gpio-hal/gpio-hal-example.c b/examples/dev/gpio-hal/gpio-hal-example.c index 040df3b38..380c06388 100644 --- a/examples/dev/gpio-hal/gpio-hal-example.c +++ b/examples/dev/gpio-hal/gpio-hal-example.c @@ -36,6 +36,7 @@ #include "dev/button-hal.h" #include +#include /*---------------------------------------------------------------------------*/ extern gpio_hal_pin_t out_pin1, out_pin2, out_pin3; extern gpio_hal_pin_t btn_pin; @@ -43,6 +44,13 @@ extern gpio_hal_pin_t btn_pin; static struct etimer et; static uint8_t counter; /*---------------------------------------------------------------------------*/ +/* Print gpio_hal_pin_mask_t using the correct format */ +#if GPIO_HAL_PIN_COUNT > 32 +#define PIN_MASK_FMT PRIx64 +#else +#define PIN_MASK_FMT PRIx32 +#endif +/*---------------------------------------------------------------------------*/ PROCESS(gpio_hal_example, "GPIO HAL Example"); AUTOSTART_PROCESSES(&gpio_hal_example); /*---------------------------------------------------------------------------*/ @@ -119,7 +127,8 @@ PROCESS_THREAD(gpio_hal_example, ev, data) } /* Test read */ - printf("%u: Pins are 1-%u, 2=%u, 3=%u, mask=0x%08lx\n", counter & 7, + printf("%u: Pins are 1-%u, 2=%u, 3=%u, mask=0x%08" PIN_MASK_FMT "\n", + counter & 7, gpio_hal_arch_read_pin(out_pin1), gpio_hal_arch_read_pin(out_pin2), gpio_hal_arch_read_pin(out_pin3), From 75491b2213f04e7807640291704d9301e8db859a Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 1 Apr 2018 15:42:03 +0100 Subject: [PATCH 010/129] Add native support to the GPIO HAL example --- examples/dev/gpio-hal/Makefile | 2 +- examples/dev/gpio-hal/native/pins.c | 40 +++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 examples/dev/gpio-hal/native/pins.c diff --git a/examples/dev/gpio-hal/Makefile b/examples/dev/gpio-hal/Makefile index efbdf6e05..016f53377 100644 --- a/examples/dev/gpio-hal/Makefile +++ b/examples/dev/gpio-hal/Makefile @@ -1,7 +1,7 @@ CONTIKI_PROJECT = gpio-hal-example CONTIKI = ../../.. -PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul +PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul native include $(CONTIKI)/Makefile.identify-target diff --git a/examples/dev/gpio-hal/native/pins.c b/examples/dev/gpio-hal/native/pins.c new file mode 100644 index 000000000..10472b78a --- /dev/null +++ b/examples/dev/gpio-hal/native/pins.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, George Oikonomou - http://www.spd.gr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "dev/gpio-hal.h" +/*---------------------------------------------------------------------------*/ +gpio_hal_pin_t out_pin1 = 0; +gpio_hal_pin_t out_pin2 = 1; +gpio_hal_pin_t out_pin3 = 2; +/*---------------------------------------------------------------------------*/ +gpio_hal_pin_t btn_pin = 4; +/*---------------------------------------------------------------------------*/ From fab1dcc96ce020284ac642d67cc790249f716fc5 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 1 Apr 2018 15:44:41 +0100 Subject: [PATCH 011/129] Add native support to the button HAL example --- examples/dev/button-hal/Makefile | 2 +- examples/dev/button-hal/button-hal-example.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/dev/button-hal/Makefile b/examples/dev/button-hal/Makefile index 071ec02ec..0c209918c 100644 --- a/examples/dev/button-hal/Makefile +++ b/examples/dev/button-hal/Makefile @@ -3,6 +3,6 @@ CONTIKI = ../../.. all: $(CONTIKI_PROJECT) -PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul +PLATFORMS_ONLY = srf06-cc26xx cc2538dk openmote-cc2538 zoul native include $(CONTIKI)/Makefile.include diff --git a/examples/dev/button-hal/button-hal-example.c b/examples/dev/button-hal/button-hal-example.c index b4d584e3e..db34b86af 100644 --- a/examples/dev/button-hal/button-hal-example.c +++ b/examples/dev/button-hal/button-hal-example.c @@ -47,10 +47,13 @@ PROCESS_THREAD(button_hal_example, ev, data) printf("Button HAL example.\n"); printf("Device button count: %u.\n", button_hal_button_count); - printf("%s on pin %u with ID=0, Logic=%s, Pull=%s\n", - BUTTON_HAL_GET_DESCRIPTION(btn), btn->pin, - btn->negative_logic ? "Negative" : "Positive", - btn->pull == GPIO_HAL_PIN_CFG_PULL_UP ? "Pull Up" : "Pull Down"); + + if(btn) { + printf("%s on pin %u with ID=0, Logic=%s, Pull=%s\n", + BUTTON_HAL_GET_DESCRIPTION(btn), btn->pin, + btn->negative_logic ? "Negative" : "Positive", + btn->pull == GPIO_HAL_PIN_CFG_PULL_UP ? "Pull Up" : "Pull Down"); + } while(1) { From a94b868a4f2b171236146aa5bd74ec1b5f89763f Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sun, 1 Apr 2018 14:01:31 +0100 Subject: [PATCH 012/129] Tidy-up AROPTS for cpu native --- arch/cpu/native/Makefile.native | 2 +- arch/platform/native/Makefile.native | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/cpu/native/Makefile.native b/arch/cpu/native/Makefile.native index cda288e65..146af3e72 100644 --- a/arch/cpu/native/Makefile.native +++ b/arch/cpu/native/Makefile.native @@ -20,7 +20,7 @@ CFLAGSNO = -Wall -g -I/usr/local/include $(CFLAGSWERROR) CFLAGS += $(CFLAGSNO) ifeq ($(HOST_OS),Darwin) -AROPTS = -r +AROPTS = -rc LDFLAGS += -Wl,-flat_namespace,-map,$(CONTIKI_NG_PROJECT_MAP) CFLAGS += -DHAVE_SNPRINTF=1 -U__ASSERT_USE_STDERR else diff --git a/arch/platform/native/Makefile.native b/arch/platform/native/Makefile.native index 24f433796..f8fd7286c 100644 --- a/arch/platform/native/Makefile.native +++ b/arch/platform/native/Makefile.native @@ -2,9 +2,6 @@ ifndef CONTIKI $(error CONTIKI not defined! You must specify where CONTIKI resides!) endif -ifeq ($(HOST_OS),Darwin) - AROPTS = rc -endif CONTIKI_TARGET_DIRS = . dev CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} From 6ce1c79f8c9a767ed3691a8c6ace56b2b9a78248 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 6 Apr 2018 18:20:00 +0200 Subject: [PATCH 013/129] Updated example-lwm2m-standalone to latest version --- tests/18-coap-lwm2m/example-lwm2m-standalone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/18-coap-lwm2m/example-lwm2m-standalone b/tests/18-coap-lwm2m/example-lwm2m-standalone index 7ab51eaaa..67b858437 160000 --- a/tests/18-coap-lwm2m/example-lwm2m-standalone +++ b/tests/18-coap-lwm2m/example-lwm2m-standalone @@ -1 +1 @@ -Subproject commit 7ab51eaaa309c123fbd318c6ad3338cce1e48e48 +Subproject commit 67b858437f7cf1e4e027d821c4c2ac15fdf2ab44 From c81459e565f8057b7a5aefefe9b4497e56a940ed Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 6 Apr 2018 18:22:53 +0200 Subject: [PATCH 014/129] Fixed some issues with the LWM2M IPSO and standalone regressing tests. --- tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh | 13 +++++++++++-- .../18-coap-lwm2m/07-lwm2m-standalone-test.sh | 19 ++++++++++++++----- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh b/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh index 15fd96243..7684044a8 100755 --- a/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh +++ b/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh @@ -3,12 +3,13 @@ # Contiki directory CONTIKI=$1 # Test basename -BASENAME=06-lwm2m-test +BASENAME=06-lwm2m-ipso-test IPADDR=fd00::302:304:506:708 # Starting Contiki-NG native node echo "Starting native node - lwm2m/ipso objects" +make -C $CONTIKI/examples/ipso-objects clean >/dev/null make -C $CONTIKI/examples/ipso-objects > make.log 2> make.err sudo $CONTIKI/examples/ipso-objects/example-ipso-objects.native > node.log 2> node.err & CPID=$! @@ -19,7 +20,15 @@ wget -nc https://joakimeriksson.github.io/resources/leshan-server-demo-1.0.0-SNA echo "Starting leshan server" java -jar leshan-server-demo-1.0.0-SNAPSHOT-jar-with-dependencies.jar >leshan.log 2>leshan.err & LESHID=$! -sleep 50 + +COUNTER=10 +while [ $COUNTER -gt 0 ]; do + sleep 5 + if grep -q 'OK' leshan.err ; then + break + fi + let COUNTER-=1 +done echo "Closing native node" sleep 1 diff --git a/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh b/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh index 5516eeb46..b13352447 100755 --- a/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh +++ b/tests/18-coap-lwm2m/07-lwm2m-standalone-test.sh @@ -5,9 +5,10 @@ CONTIKI=$1 # Test basename BASENAME=07-lwm2m-standalone-test -git clone https://github.com/contiki-ng/example-lwm2m-standalone.git # Building standalone posix example -make -C example-lwm2m-standalone/lwm2m > make.log 2> make.err +echo "Compiling standalone posix example" +make CONTIKI_NG=../../$CONTIKI -C example-lwm2m-standalone/lwm2m clean >/dev/null +make CONTIKI_NG=../../$CONTIKI -C example-lwm2m-standalone/lwm2m >make.log 2>make.err echo "Downloading leshan" wget -nc https://joakimeriksson.github.io/resources/leshan-server-demo-1.0.0-SNAPSHOT-jar-with-dependencies.jar @@ -20,11 +21,19 @@ example-lwm2m-standalone/lwm2m/lwm2m-example coap://127.0.0.1:5686 > node.log 2> CPID=$! -sleep 50 +COUNTER=10 +while [ $COUNTER -gt 0 ]; do + sleep 5 + if grep -q 'OK' leshan.err ; then + echo OK with $COUNTER + break + fi + let COUNTER-=1 +done -echo "Closing native node" +echo "Closing standalone example" sleep 1 -pgrep ipso | sudo xargs kill -9 +pgrep lwm2m-example | sudo xargs kill -9 echo "Closing leshan" sleep 1 From c48173eb5bf3a29c84465ec35547c53aab941865 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 24 Mar 2018 07:40:52 -0700 Subject: [PATCH 015/129] RPL Lite: whenever hearing an old version from the root, reset DIO timer to let the root know about the current version --- os/net/routing/rpl-lite/rpl-dag.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index 00ee1663e..a2a18c59a 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -395,9 +395,15 @@ process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio) return; } - /* If the DIO sender is on an older version of the DAG, ignore it. The node - will eventually hear the global repair and catch up. */ + /* If the DIO sender is on an older version of the DAG, do not process it + * further. The sender will eventually hear the global repair and catch up. */ if(rpl_lollipop_greater_than(curr_instance.dag.version, dio->version)) { + if(dio->rank == ROOT_RANK) { + /* Before returning, if the DIO was from the root, an old DAG versions + * likely incidates a root reboot. Reset our DIO timer to make sure the + * root hears our version ASAP, and in trun triggers a global repair. */ + rpl_timers_dio_reset("Heard old version from root"); + } return; } @@ -412,10 +418,12 @@ process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio) * Must come first, as it might remove all neighbors, and we then need * to re-add this source of the DIO to the neighbor table */ if(rpl_lollipop_greater_than(dio->version, curr_instance.dag.version)) { - if(curr_instance.dag.rank == ROOT_RANK) { /* The root should not hear newer versions */ + if(curr_instance.dag.rank == ROOT_RANK) { + /* The root should not hear newer versions unless it just rebooted */ LOG_ERR("inconsistent DIO version (current: %u, received: %u), initiate global repair\n", curr_instance.dag.version, dio->version); - curr_instance.dag.version = dio->version; /* Update version and trigger global repair */ + /* Update version and trigger global repair */ + curr_instance.dag.version = dio->version; rpl_global_repair("Inconsistent DIO version"); } else { LOG_WARN("new DIO version (current: %u, received: %u), apply global repair\n", From 58261ad53ea9c46f2783bcc5370695bc574843bb Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 7 Apr 2018 14:19:58 +0100 Subject: [PATCH 016/129] Delete trailing whitespaces (tests/) --- os/lib/dbg-io/strformat.h | 2 +- os/net/routing/rpl-classic/rpl-dag.c | 4 ++-- os/sys/stack-check.h | 1 - tests/07-simulation-base/js/04-ringbufindex.js | 3 +-- tests/07-simulation-base/js/22-stack-check.js | 4 ++-- tests/13-ieee802154/js/sixtop-test.js | 1 - 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/os/lib/dbg-io/strformat.h b/os/lib/dbg-io/strformat.h index 62d99b303..478fb7af7 100644 --- a/os/lib/dbg-io/strformat.h +++ b/os/lib/dbg-io/strformat.h @@ -53,7 +53,7 @@ typedef struct strformat_context_s { /*---------------------------------------------------------------------------*/ int format_str(const strformat_context_t *ctxt, const char *format, ...) __attribute__ ((__format__ (__printf__, 2,3))); - + int format_str_v(const strformat_context_t *ctxt, const char *format, va_list ap); /*---------------------------------------------------------------------------*/ diff --git a/os/net/routing/rpl-classic/rpl-dag.c b/os/net/routing/rpl-classic/rpl-dag.c index 899322264..742ef16c4 100644 --- a/os/net/routing/rpl-classic/rpl-dag.c +++ b/os/net/routing/rpl-classic/rpl-dag.c @@ -829,7 +829,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p) if(best_dag->preferred_parent != last_parent) { rpl_set_default_route(instance, rpl_parent_get_ipaddr(best_dag->preferred_parent)); PRINTF("RPL: Changed preferred parent, rank changed from %u to %u\n", - (unsigned)old_rank, best_dag->rank); + (unsigned)old_rank, best_dag->rank); RPL_STAT(rpl_stats.parent_switch++); if(RPL_IS_STORING(instance)) { if(last_parent != NULL) { @@ -848,7 +848,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p) #endif } else if(best_dag->rank != old_rank) { PRINTF("RPL: Preferred parent update, rank changed from %u to %u\n", - (unsigned)old_rank, best_dag->rank); + (unsigned)old_rank, best_dag->rank); } return best_dag; } diff --git a/os/sys/stack-check.h b/os/sys/stack-check.h index a9068f216..805c4b7da 100644 --- a/os/sys/stack-check.h +++ b/os/sys/stack-check.h @@ -45,7 +45,6 @@ * On startup, fills the area between the stack and the heap with a known pattern. * During execution, the fill can be checked in order to find out * the extent to which the stack has been used. - * * * @{ */ diff --git a/tests/07-simulation-base/js/04-ringbufindex.js b/tests/07-simulation-base/js/04-ringbufindex.js index 153f920af..5acb27f11 100644 --- a/tests/07-simulation-base/js/04-ringbufindex.js +++ b/tests/07-simulation-base/js/04-ringbufindex.js @@ -6,7 +6,7 @@ while(true) { YIELD(); log.log(time + " " + "node-" + id + " "+ msg + "\n"); - + if(msg.contains("=check-me=") == false) { continue; } @@ -23,4 +23,3 @@ if(failed) { log.testFailed(); } log.testOK(); - diff --git a/tests/07-simulation-base/js/22-stack-check.js b/tests/07-simulation-base/js/22-stack-check.js index c6915cc66..3dd0b381c 100644 --- a/tests/07-simulation-base/js/22-stack-check.js +++ b/tests/07-simulation-base/js/22-stack-check.js @@ -11,12 +11,12 @@ while(true) { log.log("> " + msg + "\n"); var found = msg.match(re); - + if(found) { var n = parseInt(found[1]); minusage = minusage < n ? minusage : n; maxusage = maxusage > n ? maxusage : n; - + if(minusage < 800 && maxusage >= 1000) { log.testOK(); } diff --git a/tests/13-ieee802154/js/sixtop-test.js b/tests/13-ieee802154/js/sixtop-test.js index 962182e33..c410644ec 100644 --- a/tests/13-ieee802154/js/sixtop-test.js +++ b/tests/13-ieee802154/js/sixtop-test.js @@ -24,4 +24,3 @@ if(failed) { log.testFailed(); } log.testOK(); - From f88b195de4c8972f5d77baabd33e38b04ae17184 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 7 Apr 2018 14:21:23 +0100 Subject: [PATCH 017/129] Delete trailing whitespaces (examples/) --- examples/platform-specific/cc26xx/ble-ipv6/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/platform-specific/cc26xx/ble-ipv6/README.md b/examples/platform-specific/cc26xx/ble-ipv6/README.md index d72ab752d..d33c7329f 100644 --- a/examples/platform-specific/cc26xx/ble-ipv6/README.md +++ b/examples/platform-specific/cc26xx/ble-ipv6/README.md @@ -6,7 +6,7 @@ can be exchanged using BLE connections (IPv6 over BLE). This Contiki extenstion implements [BLEach][bleachWeb], a fully open-source IPv6-over-BLE stack for Contiki. BLEach in Contiki-NG can be used for node (BLE slave) devices. -It was developed by +It was developed by * [Michael Spoerk](http://www.michaelspoerk.com), Graz University of Technology, michael.spoerk@tugraz.at, github user: [spoerk](https://github.com/spoerk) This IPv6-over-BLE stack is presented and evaluated in the paper: @@ -21,7 +21,7 @@ This implementation includes: * BLE link layer support for version [4.1][bleSpec]: * BLE advertisement * BLE connection slave - + It has been tested on the TI CC2650 SensorTag and the TI CC2650 LaunchPad hardware. ## Modules @@ -78,4 +78,3 @@ specifies the used advertisement interval in milliseconds. [rfc7668]: https://tools.ietf.org/html/rfc7668 [bleSpec]: https://www.bluetooth.com/specifications/bluetooth-core-specification/legacy-specifications [bleachWeb]: http://www.iti.tugraz.at/BLEach - From f6bd7ba47a30c28ae808b662a4a5e40d7740db13 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 7 Apr 2018 14:32:00 +0100 Subject: [PATCH 018/129] Fix code style --- arch/dev/ext-flash/ext-flash.c | 14 ++++--- arch/platform/srf06-cc26xx/cfs-coffee-arch.h | 43 +++++++++----------- arch/platform/srf06-cc26xx/common/xmem.c | 29 +++++-------- 3 files changed, 39 insertions(+), 47 deletions(-) diff --git a/arch/dev/ext-flash/ext-flash.c b/arch/dev/ext-flash/ext-flash.c index 547ec062c..10e953ffa 100644 --- a/arch/dev/ext-flash/ext-flash.c +++ b/arch/dev/ext-flash/ext-flash.c @@ -113,13 +113,15 @@ static spi_device_t flash_spi_configuration_default = { /** * Get spi configuration, return default configuration if NULL */ -static spi_device_t* -get_spi_conf(spi_device_t *conf) { +static spi_device_t * +get_spi_conf(spi_device_t *conf) +{ if(conf == NULL) { return &flash_spi_configuration_default; } return conf; -}/*---------------------------------------------------------------------------*/ +} +/*---------------------------------------------------------------------------*/ /** * Clear external flash CSN line */ @@ -334,7 +336,7 @@ ext_flash_open(spi_device_t *conf) /* Put the part is standby mode */ power_standby(flash_spi_configuration); - if (verify_part(flash_spi_configuration) == VERIFY_PART_OK) { + if(verify_part(flash_spi_configuration) == VERIFY_PART_OK) { return true; } @@ -353,7 +355,7 @@ ext_flash_close(spi_device_t *conf) /* Put the part in low power mode */ ret = power_down(flash_spi_configuration); - + /* SPI is released no matter if power_down() succeeds or fails */ if(spi_release(flash_spi_configuration) != SPI_DEV_STATUS_OK) { return false; @@ -474,7 +476,7 @@ ext_flash_erase(spi_device_t *conf, uint32_t offset, uint32_t length) uint8_t wbuf[4]; uint32_t i, numsectors; uint32_t endoffset = offset + length - 1; - + spi_device_t *flash_spi_configuration; flash_spi_configuration = get_spi_conf(conf); diff --git a/arch/platform/srf06-cc26xx/cfs-coffee-arch.h b/arch/platform/srf06-cc26xx/cfs-coffee-arch.h index 33cc5123b..6816ca043 100644 --- a/arch/platform/srf06-cc26xx/cfs-coffee-arch.h +++ b/arch/platform/srf06-cc26xx/cfs-coffee-arch.h @@ -43,44 +43,41 @@ #include "contiki-conf.h" #include "dev/xmem.h" -/*** MX25R8035F Memory Organization -The memory is organized as: -8Mbit = 1048576 bytes (8 bits each) -256 sectors (32 Kbits, 4096 bytes each) -4096 pages (256 bytes each). -Each page can be individually programmed (bits are programmed from 1 to 0). The device is -sector or bulk erasable (bits are erased from 0 to 1) but not page erasable -*/ -#define COFFEE_XMEM_TOTAL_SIZE_KB 1024UL //Total size of the External Flash Memory in the Z1 +/* + * MX25R8035F Memory Organization + * The memory is organized as: + * 8Mbit = 1048576 bytes (8 bits each) + * 256 sectors (32 Kbits, 4096 bytes each) + * 4096 pages (256 bytes each). + * Each page can be individually programmed (bits are programmed from 1 to 0). + * The device is sector or bulk erasable (bits are erased from 0 to 1) but not + * page erasable + */ +#define COFFEE_XMEM_TOTAL_SIZE_KB 1024UL /* Total size of the External Flash Memory in the Z1 */ /* Coffee configuration parameters. */ -#define COFFEE_SECTOR_SIZE 4096UL +#define COFFEE_SECTOR_SIZE 4096UL #define COFFEE_PAGE_SIZE 256UL -#define COFFEE_START 0UL //COFFEE_SECTOR_SIZE +#define COFFEE_START 0UL /* COFFEE_SECTOR_SIZE */ #define COFFEE_SIZE (COFFEE_XMEM_TOTAL_SIZE_KB * 1024UL - COFFEE_START) #define COFFEE_NAME_LENGTH 16 #define COFFEE_MAX_OPEN_FILES 6 #define COFFEE_FD_SET_SIZE 8 #define COFFEE_LOG_TABLE_LIMIT 256 -#define COFFEE_DYN_SIZE 2*1024 +#define COFFEE_DYN_SIZE 2 * 1024 #define COFFEE_LOG_SIZE 1024 #define COFFEE_MICRO_LOGS 1 - - - - - /* Flash operations. */ -#define COFFEE_WRITE(buf, size, offset) \ - xmem_pwrite((char *)(buf), (size), COFFEE_START + (offset)) +#define COFFEE_WRITE(buf, size, offset) \ + xmem_pwrite((char *)(buf), (size), COFFEE_START + (offset)) -#define COFFEE_READ(buf, size, offset) \ - xmem_pread((char *)(buf), (size), COFFEE_START + (offset)) +#define COFFEE_READ(buf, size, offset) \ + xmem_pread((char *)(buf), (size), COFFEE_START + (offset)) -#define COFFEE_ERASE(sector) \ - xmem_erase(COFFEE_SECTOR_SIZE, COFFEE_START + (sector) * COFFEE_SECTOR_SIZE) +#define COFFEE_ERASE(sector) \ + xmem_erase(COFFEE_SECTOR_SIZE, COFFEE_START + (sector) * COFFEE_SECTOR_SIZE) /* Coffee types. */ typedef int16_t coffee_page_t; diff --git a/arch/platform/srf06-cc26xx/common/xmem.c b/arch/platform/srf06-cc26xx/common/xmem.c index 116991c66..9228e0fbb 100644 --- a/arch/platform/srf06-cc26xx/common/xmem.c +++ b/arch/platform/srf06-cc26xx/common/xmem.c @@ -49,21 +49,17 @@ #define XMEM_BUFF_LENGHT 128 - #if 0 #define PRINTF(...) printf(__VA_ARGS__) #else -#define PRINTF(...) do {} while (0) +#define PRINTF(...) do {} while(0) #endif - void xmem_init(void) { ext_flash_open(NULL); } - - int xmem_pread(void *_p, int size, unsigned long addr) { @@ -80,21 +76,20 @@ xmem_pread(void *_p, int size, unsigned long addr) } rv = ext_flash_read(NULL, addr, size, _p); - for (i = 0; i < size; i++){ + for(i = 0; i < size; i++) { x = ~*((uint8_t *)_p + i); - *((uint8_t *)_p+i) = x; + *((uint8_t *)_p + i) = x; } ext_flash_close(NULL); - if(rv) + if(rv) { return size; + } PRINTF("Could not read flash memory!\n"); return -1; -} - - +} int xmem_pwrite(const void *_buf, int size, unsigned long addr) { @@ -112,13 +107,13 @@ xmem_pwrite(const void *_buf, int size, unsigned long addr) return -1; } - for (remain = size, j = 0; remain > 0; remain -= XMEM_BUFF_LENGHT, j += XMEM_BUFF_LENGHT) { + for(remain = size, j = 0; remain > 0; remain -= XMEM_BUFF_LENGHT, j += XMEM_BUFF_LENGHT) { int to_write = MIN(XMEM_BUFF_LENGHT, remain); - for (i = 0; i < to_write; i++) { + for(i = 0; i < to_write; i++) { tmp_buf[i] = ~*((uint8_t *)_buf + j + i); } rv = ext_flash_write(NULL, addr + j, to_write, tmp_buf); - if (!rv) { + if(!rv) { PRINTF("Could not write flash memory!\n"); return size - remain; } @@ -128,8 +123,6 @@ xmem_pwrite(const void *_buf, int size, unsigned long addr) return size; } - - int xmem_erase(long size, unsigned long addr) { @@ -137,7 +130,6 @@ xmem_erase(long size, unsigned long addr) rv = ext_flash_open(NULL); - if(!rv) { PRINTF("Could not open flash to save config\n"); ext_flash_close(NULL); @@ -160,8 +152,9 @@ xmem_erase(long size, unsigned long addr) watchdog_periodic(); - if(rv) + if(rv) { return size; + } PRINTF("Could not erase flash memory\n"); return -1; From f254d22bf38e0af88c86bdd455df1597337724ff Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 7 Apr 2018 14:35:43 +0100 Subject: [PATCH 019/129] Delete trailing whitespaces (various leds-arch.c files) --- arch/platform/cc2538dk/dev/leds-arch.c | 2 -- arch/platform/openmote-cc2538/dev/leds-arch.c | 2 -- arch/platform/srf06-cc26xx/launchpad/leds-arch.c | 2 -- arch/platform/srf06-cc26xx/sensortag/cc1350/leds-arch.c | 2 -- arch/platform/srf06-cc26xx/sensortag/cc2650/leds-arch.c | 2 -- arch/platform/srf06-cc26xx/srf06/leds-arch.c | 2 -- arch/platform/zoul/dev/leds-arch.c | 2 -- 7 files changed, 14 deletions(-) diff --git a/arch/platform/cc2538dk/dev/leds-arch.c b/arch/platform/cc2538dk/dev/leds-arch.c index c849355b4..78441defc 100644 --- a/arch/platform/cc2538dk/dev/leds-arch.c +++ b/arch/platform/cc2538dk/dev/leds-arch.c @@ -57,5 +57,3 @@ const leds_t leds_arch_leds[] = { #endif }; /*---------------------------------------------------------------------------*/ - - diff --git a/arch/platform/openmote-cc2538/dev/leds-arch.c b/arch/platform/openmote-cc2538/dev/leds-arch.c index 2bc13bed8..3c1fe333f 100644 --- a/arch/platform/openmote-cc2538/dev/leds-arch.c +++ b/arch/platform/openmote-cc2538/dev/leds-arch.c @@ -54,5 +54,3 @@ const leds_t leds_arch_leds[] = { }, }; /*---------------------------------------------------------------------------*/ - - diff --git a/arch/platform/srf06-cc26xx/launchpad/leds-arch.c b/arch/platform/srf06-cc26xx/launchpad/leds-arch.c index 5d70dea40..3c483d3bd 100644 --- a/arch/platform/srf06-cc26xx/launchpad/leds-arch.c +++ b/arch/platform/srf06-cc26xx/launchpad/leds-arch.c @@ -41,5 +41,3 @@ const leds_t leds_arch_leds[] = { { .pin = BOARD_IOID_LED_2, .negative_logic = false }, }; /*---------------------------------------------------------------------------*/ - - diff --git a/arch/platform/srf06-cc26xx/sensortag/cc1350/leds-arch.c b/arch/platform/srf06-cc26xx/sensortag/cc1350/leds-arch.c index 21b8cf968..8da95520f 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc1350/leds-arch.c +++ b/arch/platform/srf06-cc26xx/sensortag/cc1350/leds-arch.c @@ -39,5 +39,3 @@ const leds_t leds_arch_leds[] = { { .pin = BOARD_IOID_LED_1, .negative_logic = false }, }; /*---------------------------------------------------------------------------*/ - - diff --git a/arch/platform/srf06-cc26xx/sensortag/cc2650/leds-arch.c b/arch/platform/srf06-cc26xx/sensortag/cc2650/leds-arch.c index cab4888b7..ac4abb7d5 100644 --- a/arch/platform/srf06-cc26xx/sensortag/cc2650/leds-arch.c +++ b/arch/platform/srf06-cc26xx/sensortag/cc2650/leds-arch.c @@ -40,5 +40,3 @@ const leds_t leds_arch_leds[] = { { .pin = BOARD_IOID_LED_2, .negative_logic = false }, }; /*---------------------------------------------------------------------------*/ - - diff --git a/arch/platform/srf06-cc26xx/srf06/leds-arch.c b/arch/platform/srf06-cc26xx/srf06/leds-arch.c index fba996b39..f504f9cc2 100644 --- a/arch/platform/srf06-cc26xx/srf06/leds-arch.c +++ b/arch/platform/srf06-cc26xx/srf06/leds-arch.c @@ -42,5 +42,3 @@ const leds_t leds_arch_leds[] = { { .pin = BOARD_IOID_LED_4, .negative_logic = false }, }; /*---------------------------------------------------------------------------*/ - - diff --git a/arch/platform/zoul/dev/leds-arch.c b/arch/platform/zoul/dev/leds-arch.c index eea4187c0..ecb02b2f6 100644 --- a/arch/platform/zoul/dev/leds-arch.c +++ b/arch/platform/zoul/dev/leds-arch.c @@ -50,5 +50,3 @@ const leds_t leds_arch_leds[] = { }, }; /*---------------------------------------------------------------------------*/ - - From 3299780bbeae9a76c665f7129abf887e71d6f384 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 7 Apr 2018 14:36:10 +0100 Subject: [PATCH 020/129] Delete trailing whitespaces (arch/cpu/) --- arch/cpu/cc2538/dev/spi-arch-legacy.h | 16 ++++----- arch/cpu/msp430/f1xxx/spi-legacy.c | 48 +++++++++++++-------------- arch/cpu/msp430/msp430-def.h | 46 ++++++++++++------------- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/arch/cpu/cc2538/dev/spi-arch-legacy.h b/arch/cpu/cc2538/dev/spi-arch-legacy.h index de7a765bb..9608110ed 100644 --- a/arch/cpu/cc2538/dev/spi-arch-legacy.h +++ b/arch/cpu/cc2538/dev/spi-arch-legacy.h @@ -55,7 +55,7 @@ * - SPIX_FLUSH(x) * * Some of the old functions and macros are still supported. - * When using these deprecated functions, the SSI module to use + * When using these deprecated functions, the SSI module to use * has to be be selected by means of the macro SPI_CONF_DEFAULT_INSTANCE. * * This SPI driver depends on the following defines: @@ -95,14 +95,14 @@ #endif /*---------------------------------------------------------------------------*/ /* Default values for the clock rate divider */ -#ifdef SPI0_CONF_CPRS_CPSDVSR -#define SPI0_CPRS_CPSDVSR SPI0_CONF_CPRS_CPSDVSR +#ifdef SPI0_CONF_CPRS_CPSDVSR +#define SPI0_CPRS_CPSDVSR SPI0_CONF_CPRS_CPSDVSR #else #define SPI0_CPRS_CPSDVSR 2 #endif -#ifdef SPI1_CONF_CPRS_CPSDVSR -#define SPI1_CPRS_CPSDVSR SPI1_CONF_CPRS_CPSDVSR +#ifdef SPI1_CONF_CPRS_CPSDVSR +#define SPI1_CPRS_CPSDVSR SPI1_CONF_CPRS_CPSDVSR #else #define SPI1_CPRS_CPSDVSR 2 #endif @@ -120,7 +120,7 @@ } while(0) #define SPIX_FLUSH(spi) do { \ while(REG(SSI_BASE(spi) + SSI_SR) & SSI_SR_RNE) { \ - SPIX_BUF(spi); \ + SPIX_BUF(spi); \ } \ } while(0) #define SPIX_CS_CLR(port, pin) do { \ @@ -144,7 +144,7 @@ #endif #define SPI_CS_CLR(port, pin) SPIX_CS_CLR(port, pin) #define SPI_CS_SET(port, pin) SPIX_CS_SET(port, pin) -#endif /* #ifdef SPI_DEFAULT_INSTANCE */ +#endif /* #ifdef SPI_DEFAULT_INSTANCE */ /*---------------------------------------------------------------------------*/ /** \name Arch-specific SPI functions * @{ @@ -183,7 +183,7 @@ void spix_disable(uint8_t spi); * * See section 19.4.4 in the CC2538 user guide for more information. * - * \param spi The SSI instance to use. + * \param spi The SSI instance to use. * \param frame_format Set the SSI frame format. Use SSI_CR0_FRF_MOTOROLA, * SSI_CR0_FRF_TI, or SSI_CR0_FRF_MICROWIRE. * \param clock_polarity In Motorola mode, set whether the clock is high or low diff --git a/arch/cpu/msp430/f1xxx/spi-legacy.c b/arch/cpu/msp430/f1xxx/spi-legacy.c index c9e98508f..38adfaa31 100644 --- a/arch/cpu/msp430/f1xxx/spi-legacy.c +++ b/arch/cpu/msp430/f1xxx/spi-legacy.c @@ -1,30 +1,30 @@ /* * Copyright (c) 2006, Swedish Institute of Computer Science - * All rights reserved. + * All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. * */ @@ -35,7 +35,7 @@ * exclusive. Set spi_busy so that interrupt handlers can check if * they are allowed to use the bus or not. Only the CC2420 radio needs * this in practice. - * + * */ unsigned char spi_busy = 0; diff --git a/arch/cpu/msp430/msp430-def.h b/arch/cpu/msp430/msp430-def.h index 93e575702..e032bb4a0 100644 --- a/arch/cpu/msp430/msp430-def.h +++ b/arch/cpu/msp430/msp430-def.h @@ -1,30 +1,30 @@ /* * Copyright (c) 2007, Swedish Institute of Computer Science - * All rights reserved. + * All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ #ifndef MSP430_DEF_H_ From 9b2fbdcae8a0185fc1f5ced88bbeee51b786b4a9 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 7 Apr 2018 14:23:14 +0100 Subject: [PATCH 021/129] Update top-level README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f29f369c1..df7d7ff58 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Contiki-NG: The OS for Next Generation IoT Devices [![Build Status](https://travis-ci.org/contiki-ng/contiki-ng.svg?branch=master)](https://travis-ci.org/contiki-ng/contiki-ng/branches) -[![License](https://img.shields.io/badge/License-3--Clause%20BSD-brightgreen.svg)](https://github.com/contiki-ng/contiki-ng/blob/master/LICENSE.md) +[![license](https://img.shields.io/badge/license-3--clause%20bsd-brightgreen.svg)](https://github.com/contiki-ng/contiki-ng/blob/master/LICENSE.md) [![Latest release](https://img.shields.io/github/release/contiki-ng/contiki-ng.svg)](https://github.com/contiki-ng/contiki-ng/releases/latest) [![GitHub Release Date](https://img.shields.io/github/release-date/contiki-ng/contiki-ng.svg)](https://github.com/contiki-ng/contiki-ng/releases/latest) [![Last commit](https://img.shields.io/github/last-commit/contiki-ng/contiki-ng.svg)](https://github.com/contiki-ng/contiki-ng/commit/HEAD) @@ -9,7 +9,7 @@ Contiki-NG is an open-source, cross-platform operating system for Next-Generation IoT devices. It focuses on dependable (secure and reliable) low-power communication and standard protocols, such as IPv6/6LoWPAN, 6TiSCH, RPL, and CoAP. Contiki-NG comes with extensive documentation, tutorials, a roadmap, release cycle, and well-defined development flow for smooth integration of community contributions. Unless excplicitly stated otherwise, Contiki-NG sources are distributed under -the terms of the [3-clause BSD license](LICENSE.md). +the terms of the [3-clause BSD license](LICENSE.md). Contiki-NG started as a fork of the Contiki OS and retains some of its original features. From 72890cc8189244646f175b0984402f5ceab8b81f Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 09:21:54 -0700 Subject: [PATCH 022/129] Rename example ipso-objects to lwm2m-ipso-objects --- examples/{ipso-objects => lwm2m-ipso-objects}/Makefile | 0 examples/{ipso-objects => lwm2m-ipso-objects}/README.md | 0 .../example-ipso-objects.c | 0 .../example-ipso-temperature.c | 0 .../{ipso-objects => lwm2m-ipso-objects}/example-server.c | 0 .../{ipso-objects => lwm2m-ipso-objects}/project-conf.h | 0 .../{ipso-objects => lwm2m-ipso-objects}/serial-protocol.c | 0 .../{ipso-objects => lwm2m-ipso-objects}/serial-protocol.h | 0 tests/01-compile-base/Makefile | 4 ++-- tests/02-compile-arm-ports-01/Makefile | 2 +- tests/03-compile-arm-ports-02/Makefile | 4 ++-- tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh | 6 +++--- 12 files changed, 8 insertions(+), 8 deletions(-) rename examples/{ipso-objects => lwm2m-ipso-objects}/Makefile (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/README.md (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/example-ipso-objects.c (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/example-ipso-temperature.c (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/example-server.c (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/project-conf.h (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/serial-protocol.c (100%) rename examples/{ipso-objects => lwm2m-ipso-objects}/serial-protocol.h (100%) diff --git a/examples/ipso-objects/Makefile b/examples/lwm2m-ipso-objects/Makefile similarity index 100% rename from examples/ipso-objects/Makefile rename to examples/lwm2m-ipso-objects/Makefile diff --git a/examples/ipso-objects/README.md b/examples/lwm2m-ipso-objects/README.md similarity index 100% rename from examples/ipso-objects/README.md rename to examples/lwm2m-ipso-objects/README.md diff --git a/examples/ipso-objects/example-ipso-objects.c b/examples/lwm2m-ipso-objects/example-ipso-objects.c similarity index 100% rename from examples/ipso-objects/example-ipso-objects.c rename to examples/lwm2m-ipso-objects/example-ipso-objects.c diff --git a/examples/ipso-objects/example-ipso-temperature.c b/examples/lwm2m-ipso-objects/example-ipso-temperature.c similarity index 100% rename from examples/ipso-objects/example-ipso-temperature.c rename to examples/lwm2m-ipso-objects/example-ipso-temperature.c diff --git a/examples/ipso-objects/example-server.c b/examples/lwm2m-ipso-objects/example-server.c similarity index 100% rename from examples/ipso-objects/example-server.c rename to examples/lwm2m-ipso-objects/example-server.c diff --git a/examples/ipso-objects/project-conf.h b/examples/lwm2m-ipso-objects/project-conf.h similarity index 100% rename from examples/ipso-objects/project-conf.h rename to examples/lwm2m-ipso-objects/project-conf.h diff --git a/examples/ipso-objects/serial-protocol.c b/examples/lwm2m-ipso-objects/serial-protocol.c similarity index 100% rename from examples/ipso-objects/serial-protocol.c rename to examples/lwm2m-ipso-objects/serial-protocol.c diff --git a/examples/ipso-objects/serial-protocol.h b/examples/lwm2m-ipso-objects/serial-protocol.h similarity index 100% rename from examples/ipso-objects/serial-protocol.h rename to examples/lwm2m-ipso-objects/serial-protocol.h diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index 0c7e248e0..cb20757c7 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -14,8 +14,8 @@ libs/energest/sky \ libs/data-structures/native \ libs/data-structures/sky \ libs/stack-check/sky \ -ipso-objects/native \ -ipso-objects/native:MAKE_WITH_DTLS=1 \ +lwm2m-ipso-objects/native \ +lwm2m-ipso-objects/native:MAKE_WITH_DTLS=1 \ rpl-udp/sky \ rpl-border-router/native \ rpl-border-router/sky \ diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index 51b232173..1ecf59fe4 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -40,7 +40,7 @@ sensniff/cc2538dk \ rpl-udp/cc2538dk \ coap/cc2538dk \ slip-radio/cc2538dk \ -ipso-objects/cc2538dk \ +lwm2m-ipso-objects/cc2538dk \ multicast/cc2538dk \ dev/gpio-hal/cc2538dk \ dev/leds/cc2538dk \ diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index a69ec44a0..18b052f14 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -14,8 +14,8 @@ platform-specific/zoul/rtcc/zoul \ platform-specific/zoul/zoul \ coap/zoul \ multicast/zoul \ -ipso-objects/zoul \ -ipso-objects/zoul:MAKE_WITH_DTLS=1 \ +lwm2m-ipso-objects/zoul \ +lwm2m-ipso-objects/zoul:MAKE_WITH_DTLS=1 \ hello-world/zoul \ sensniff/zoul \ sensniff/zoul:ZOUL_CONF_SUB_GHZ_SNIFFER=1 \ diff --git a/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh b/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh index 7684044a8..9aacc2976 100755 --- a/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh +++ b/tests/18-coap-lwm2m/06-lwm2m-ipso-test.sh @@ -9,9 +9,9 @@ IPADDR=fd00::302:304:506:708 # Starting Contiki-NG native node echo "Starting native node - lwm2m/ipso objects" -make -C $CONTIKI/examples/ipso-objects clean >/dev/null -make -C $CONTIKI/examples/ipso-objects > make.log 2> make.err -sudo $CONTIKI/examples/ipso-objects/example-ipso-objects.native > node.log 2> node.err & +make -C $CONTIKI/examples/lwm2m-ipso-objects clean >/dev/null +make -C $CONTIKI/examples/lwm2m-ipso-objects > make.log 2> make.err +sudo $CONTIKI/examples/lwm2m-ipso-objects/example-ipso-objects.native > node.log 2> node.err & CPID=$! sleep 10 From 8b95d2258921f80bfab1c7d4b21fcfd783bf400b Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 09:26:41 -0700 Subject: [PATCH 023/129] Update lwm2m-ipso-example Readme --- examples/lwm2m-ipso-objects/README.md | 52 ++++----------------------- 1 file changed, 7 insertions(+), 45 deletions(-) diff --git a/examples/lwm2m-ipso-objects/README.md b/examples/lwm2m-ipso-objects/README.md index e9be82dcb..30cc5832f 100644 --- a/examples/lwm2m-ipso-objects/README.md +++ b/examples/lwm2m-ipso-objects/README.md @@ -1,48 +1,10 @@ -IPSO Objects Example +LWM2M with IPSO Objects Example ============================================ -This is an example of how to make use of the IPSO Object and LWM2M -implementation in Contiki. - -The LWM2M implementation is based on the Erbium CoAP implementation -and consists of two apps: lwm2m-engine and ipso-objects. The -lwm2m-engine handle the specifics of LWM2M including bootstrapping and -how read/writes of objects and resources are handled. The ipso-objects -contains implementations of some of the IPSO Smart Objects. - -The implementation was used during the IPSO Interop in May 2015, -Kista, Sweden, and was successfully tested with other -implementations. - -The examples use some of the basic IPSO object for controlling LEDs on -Contiki devices and for reading out temperature. - -##Testing IPSO-objects with Leshan - -First program a device with the examples/ipso-objects/example-ipso-objects.c - -```bash ->make example-ipso-objects.upload TARGET=zoul ->... -``` - -After that start up a native-border router or other border router on fd00::1/64 -or another prefix - NOTE: if you use another prefix you will need to change LWM2M_SERVER_ADDRESS for which the device will register - in project-conf.h: -``` -#define LWM2M_SERVER_ADDRESS "fd00::1" -``` - -Then when everything is setup you can download a Leshan and use that to -test controlling LEDs of the device. - -###Starting Leshan -```bash -wget https://hudson.eclipse.org/leshan/job/leshan/lastSuccessfulBuild/artifact/leshan-standalone.jar -java -jar ./leshan-standalone.jar -``` -Browse to leshans device page with http://127.0.0.1:8080 . - -When you have started the border-router and also Leshan you should now -start (or reboot) your IPSO Object enabled device. Within 30 seconds -you should be able to see it on the Leshan device page. +This is an OMA LWM2M example implementing IPSO Objects. +It can connect to a Leshan server out-of-the-box. +Important configuration paramters: +* `LWM2M_SERVER_ADDRESS`: the address of the server to register to (or bosstrap from) +* `REGISTER_WITH_LWM2M_BOOTSTRAP_SERVER`: set to bootstrap via `LWM2M_SERVER_ADDRESS` and then obtain the registration server address +A tutorial for setting up this example is provided on the wiki. From f5ae6b641e43dad61cff9e4e049790bb5e4c8827 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 10:48:52 -0700 Subject: [PATCH 024/129] Move ipv6-hooks examples to libs directory --- examples/{ => libs}/ipv6-hooks/Makefile | 2 +- examples/{ => libs}/ipv6-hooks/README.md | 0 examples/{ => libs}/ipv6-hooks/ipv6-hooks.c | 0 tests/01-compile-base/Makefile | 2 +- tests/03-compile-arm-ports-02/Makefile | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) rename examples/{ => libs}/ipv6-hooks/Makefile (84%) rename examples/{ => libs}/ipv6-hooks/README.md (100%) rename examples/{ => libs}/ipv6-hooks/ipv6-hooks.c (100%) diff --git a/examples/ipv6-hooks/Makefile b/examples/libs/ipv6-hooks/Makefile similarity index 84% rename from examples/ipv6-hooks/Makefile rename to examples/libs/ipv6-hooks/Makefile index be8cc953e..63085face 100644 --- a/examples/ipv6-hooks/Makefile +++ b/examples/libs/ipv6-hooks/Makefile @@ -1,5 +1,5 @@ CONTIKI_PROJECT = ipv6-hooks all: $(CONTIKI_PROJECT) -CONTIKI=../.. +CONTIKI=../../.. include $(CONTIKI)/Makefile.include diff --git a/examples/ipv6-hooks/README.md b/examples/libs/ipv6-hooks/README.md similarity index 100% rename from examples/ipv6-hooks/README.md rename to examples/libs/ipv6-hooks/README.md diff --git a/examples/ipv6-hooks/ipv6-hooks.c b/examples/libs/ipv6-hooks/ipv6-hooks.c similarity index 100% rename from examples/ipv6-hooks/ipv6-hooks.c rename to examples/libs/ipv6-hooks/ipv6-hooks.c diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index cb20757c7..76722e7f2 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -20,7 +20,7 @@ rpl-udp/sky \ rpl-border-router/native \ rpl-border-router/sky \ slip-radio/sky \ -ipv6-hooks/sky \ +libs/ipv6-hooks/sky \ nullnet/native \ TOOLS= diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index 18b052f14..8cc99d914 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -59,7 +59,7 @@ rpl-udp/openmote-cc2538 \ dev/gpio-hal/openmote-cc2538 \ dev/leds/openmote-cc2538 \ rpl-border-router/openmote-cc2538 \ -ipv6-hooks/openmote-cc2538 \ +libs/ipv6-hooks/openmote-cc2538 \ TOOLS= From 9454191b84ffdf292fec23daa3fd6344a6d0ba10 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 10:49:59 -0700 Subject: [PATCH 025/129] Renamd http-socket example to websocket --- examples/{http-socket => websocket}/Makefile | 0 examples/{http-socket => websocket}/http-example.c | 0 examples/{http-socket => websocket}/project-conf.h | 0 examples/{http-socket => websocket}/websocket-example.c | 0 examples/{http-socket => websocket}/websocket-node/Makefile | 0 .../{http-socket => websocket}/websocket-node/example-server.js | 0 tests/03-compile-arm-ports-02/Makefile | 2 +- 7 files changed, 1 insertion(+), 1 deletion(-) rename examples/{http-socket => websocket}/Makefile (100%) rename examples/{http-socket => websocket}/http-example.c (100%) rename examples/{http-socket => websocket}/project-conf.h (100%) rename examples/{http-socket => websocket}/websocket-example.c (100%) rename examples/{http-socket => websocket}/websocket-node/Makefile (100%) rename examples/{http-socket => websocket}/websocket-node/example-server.js (100%) diff --git a/examples/http-socket/Makefile b/examples/websocket/Makefile similarity index 100% rename from examples/http-socket/Makefile rename to examples/websocket/Makefile diff --git a/examples/http-socket/http-example.c b/examples/websocket/http-example.c similarity index 100% rename from examples/http-socket/http-example.c rename to examples/websocket/http-example.c diff --git a/examples/http-socket/project-conf.h b/examples/websocket/project-conf.h similarity index 100% rename from examples/http-socket/project-conf.h rename to examples/websocket/project-conf.h diff --git a/examples/http-socket/websocket-example.c b/examples/websocket/websocket-example.c similarity index 100% rename from examples/http-socket/websocket-example.c rename to examples/websocket/websocket-example.c diff --git a/examples/http-socket/websocket-node/Makefile b/examples/websocket/websocket-node/Makefile similarity index 100% rename from examples/http-socket/websocket-node/Makefile rename to examples/websocket/websocket-node/Makefile diff --git a/examples/http-socket/websocket-node/example-server.js b/examples/websocket/websocket-node/example-server.js similarity index 100% rename from examples/http-socket/websocket-node/example-server.js rename to examples/websocket/websocket-node/example-server.js diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index 8cc99d914..a4e1947e8 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -28,7 +28,7 @@ libs/logging/zoul \ 6tisch/etsi-plugtest-2017/zoul:BOARD=remote \ 6tisch/6p-packet/zoul \ 6tisch/sixtop/zoul \ -http-socket/zoul \ +websocket/zoul \ libs/timers/zoul \ libs/energest/zoul \ libs/trickle-library/zoul \ From 0c9d2b4049a9a0bcb38154c4706789eb35098754 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 10 Apr 2018 10:38:20 -0700 Subject: [PATCH 026/129] sicslowpan: when compressing, make sure never to overflow packetbuf with headers --- os/net/ipv6/sicslowpan.c | 77 ++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 22 deletions(-) diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index 4708acca7..5e4fd4f04 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -97,6 +97,7 @@ /* define the buffer as a byte array */ #define PACKETBUF_IPHC_BUF ((uint8_t *)(packetbuf_ptr + packetbuf_hdr_len)) +#define PACKETBUF_PAYLOAD_END ((uint8_t *)(packetbuf_ptr + mac_max_payload)) #define PACKETBUF_6LO_PTR (packetbuf_ptr + packetbuf_hdr_len) #define PACKETBUF_6LO_DISPATCH 0 /* 8 bit */ @@ -197,6 +198,11 @@ static int packetbuf_payload_len; */ static uint8_t uncomp_hdr_len; +/** + * mac_max_payload is the maimum payload space on the MAC frame. + */ +static int mac_max_payload; + /** * The current page (RFC 4944) */ @@ -663,8 +669,9 @@ uncompress_addr(uip_ipaddr_t *ipaddr, uint8_t const prefix[], * compress the IID. * \param link_destaddr L2 destination address, needed to compress IP * dest + * \return 1 if success, else 0 */ -static void +static int compress_hdr_iphc(linkaddr_t *link_destaddr) { uint8_t tmp, iphc0, iphc1, *next_hdr, *next_nhc; @@ -681,7 +688,23 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) LOG_DBG_("\n"); } +/* Macro used only internally, during header compression. Checks if there + * is sufficient space in packetbuf before writing any further. */ +#define CHECK_BUFFER_SPACE(writelen) do { \ + if(hc06_ptr + (writelen) >= PACKETBUF_PAYLOAD_END) { \ + LOG_WARN("Not enough packetbuf space to compress header (%u bytes, %u left). Aborting.\n", \ + (unsigned)(writelen), (unsigned)(PACKETBUF_PAYLOAD_END - hc06_ptr)); \ + return 0; \ + } \ +} while(0); + hc06_ptr = PACKETBUF_IPHC_BUF + 2; + + /* Check if there is enough space for the compressed IPv6 header, in the + * worst case (least compressed case). Extension headers and transport + * layer will be checked when they are compressed. */ + CHECK_BUFFER_SPACE(38); + /* * As we copy some bit-length fields, in the IPHC encoding bytes, * we sometimes use |= @@ -910,11 +933,13 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) NHC byte extra - before the next header here. This is due to next not being elided in that case. */ if(!IS_COMPRESSABLE_PROTO(*next_hdr)) { + CHECK_BUFFER_SPACE(1); hc06_ptr++; LOG_INFO("Keeping the next header in this ext hdr: %d\n", ext_hdr->next); } /* copy the ext-hdr into the hc06 buffer */ + CHECK_BUFFER_SPACE(len); memcpy(hc06_ptr, ext_hdr, len); /* modify the len to octets */ ext_hdr = (struct uip_ext_hdr *) hc06_ptr; @@ -944,6 +969,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) /* we can compress 12 bits of both source and dest */ *next_nhc = SICSLOWPAN_NHC_UDP_CS_P_11; LOG_INFO("IPHC: remove 12 b of both source & dest with prefix 0xFOB\n"); + CHECK_BUFFER_SPACE(1); *hc06_ptr = (uint8_t)((UIP_HTONS(udp_buf->srcport) - SICSLOWPAN_UDP_4_BIT_PORT_MIN) << 4) + @@ -954,6 +980,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) /* we can compress 8 bits of dest, leave source. */ *next_nhc = SICSLOWPAN_NHC_UDP_CS_P_01; LOG_INFO("IPHC: leave source, remove 8 bits of dest with prefix 0xF0\n"); + CHECK_BUFFER_SPACE(3); memcpy(hc06_ptr, &udp_buf->srcport, 2); *(hc06_ptr + 2) = (uint8_t)((UIP_HTONS(udp_buf->destport) - @@ -963,6 +990,7 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) /* we can compress 8 bits of src, leave dest. Copy compressed port */ *next_nhc = SICSLOWPAN_NHC_UDP_CS_P_10; LOG_INFO("IPHC: remove 8 bits of source with prefix 0xF0, leave dest. hch: %i\n", *next_nhc); + CHECK_BUFFER_SPACE(3); *hc06_ptr = (uint8_t)((UIP_HTONS(udp_buf->srcport) - SICSLOWPAN_UDP_8_BIT_PORT_MIN)); @@ -972,10 +1000,12 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) /* we cannot compress. Copy uncompressed ports, full checksum */ *next_nhc = SICSLOWPAN_NHC_UDP_CS_P_00; LOG_INFO("IPHC: cannot compress UDP headers\n"); + CHECK_BUFFER_SPACE(4); memcpy(hc06_ptr, &udp_buf->srcport, 4); hc06_ptr += 4; } /* always inline the checksum */ + CHECK_BUFFER_SPACE(2); memcpy(hc06_ptr, &udp_buf->udpchksum, 2); hc06_ptr += 2; uncomp_hdr_len += UIP_UDPH_LEN; @@ -1006,6 +1036,8 @@ compress_hdr_iphc(linkaddr_t *link_destaddr) } packetbuf_hdr_len = hc06_ptr - packetbuf_ptr; + + return 1; } /*--------------------------------------------------------------------*/ @@ -1477,7 +1509,6 @@ static uint8_t output(const linkaddr_t *localdest) { int framer_hdrlen; - int max_payload; /* The MAC address of the destination of the packet */ linkaddr_t dest; @@ -1513,6 +1544,20 @@ output(const linkaddr_t *localdest) packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, uipbuf_get_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS)); +/* Calculate NETSTACK_FRAMER's header length, that will be added in the NETSTACK_MAC */ +#ifndef SICSLOWPAN_USE_FIXED_HDRLEN + packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &dest); + framer_hdrlen = NETSTACK_FRAMER.length(); + if(framer_hdrlen < 0) { + /* Framing failed, we assume the maximum header length */ + framer_hdrlen = SICSLOWPAN_FIXED_HDRLEN; + } +#else /* USE_FRAMER_HDRLEN */ + framer_hdrlen = SICSLOWPAN_FIXED_HDRLEN; +#endif /* USE_FRAMER_HDRLEN */ + + mac_max_payload = MAC_MAX_PAYLOAD - framer_hdrlen; + /* Try to compress the headers */ #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPV6 compress_hdr_ipv6(&dest); @@ -1526,26 +1571,14 @@ output(const linkaddr_t *localdest) } #endif /* SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_6LORH */ #if SICSLOWPAN_COMPRESSION >= SICSLOWPAN_COMPRESSION_IPHC - compress_hdr_iphc(&dest); + if(compress_hdr_iphc(&dest) == 0) { + /* Warning should already be issued by function above */ + return 0; + } #endif /* SICSLOWPAN_COMPRESSION >= SICSLOWPAN_COMPRESSION_IPHC */ LOG_INFO("output: header of len %d\n", packetbuf_hdr_len); - /* Calculate NETSTACK_FRAMER's header length, that will be added in the NETSTACK_MAC. - * We calculate it here only to make a better decision of whether the outgoing packet - * needs to be fragmented or not. */ -#ifndef SICSLOWPAN_USE_FIXED_HDRLEN - packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &dest); - framer_hdrlen = NETSTACK_FRAMER.length(); - if(framer_hdrlen < 0) { - /* Framing failed, we assume the maximum header length */ - framer_hdrlen = SICSLOWPAN_FIXED_HDRLEN; - } -#else /* USE_FRAMER_HDRLEN */ - framer_hdrlen = SICSLOWPAN_FIXED_HDRLEN; -#endif /* USE_FRAMER_HDRLEN */ - - max_payload = MAC_MAX_PAYLOAD - framer_hdrlen; - if((int)uip_len - (int)uncomp_hdr_len > max_payload - (int)packetbuf_hdr_len) { + if((int)uip_len - (int)uncomp_hdr_len > mac_max_payload - (int)packetbuf_hdr_len) { #if SICSLOWPAN_CONF_FRAG /* Number of bytes processed. */ uint16_t processed_ip_out_len; @@ -1560,7 +1593,7 @@ output(const linkaddr_t *localdest) * IPv6/IPHC/HC_UDP dispatchs/headers. * The following fragments contain only the fragn dispatch. */ - int estimated_fragments = ((int)uip_len) / (max_payload - SICSLOWPAN_FRAGN_HDR_LEN) + 1; + int estimated_fragments = ((int)uip_len) / (mac_max_payload - SICSLOWPAN_FRAGN_HDR_LEN) + 1; int freebuf = queuebuf_numfree() - 1; LOG_INFO("uip_len: %d, fragments: %d, free bufs: %d\n", uip_len, estimated_fragments, freebuf); if(freebuf < estimated_fragments) { @@ -1590,7 +1623,7 @@ output(const linkaddr_t *localdest) /* Copy payload and send */ packetbuf_hdr_len += SICSLOWPAN_FRAG1_HDR_LEN; - packetbuf_payload_len = (max_payload - packetbuf_hdr_len) & 0xfffffff8; + packetbuf_payload_len = (mac_max_payload - packetbuf_hdr_len) & 0xfffffff8; LOG_INFO_("(len %d, tag %d)\n", packetbuf_payload_len, frag_tag); memcpy(packetbuf_ptr + packetbuf_hdr_len, (uint8_t *)UIP_IP_BUF + uncomp_hdr_len, packetbuf_payload_len); @@ -1626,7 +1659,7 @@ output(const linkaddr_t *localdest) /* uip_htons((SICSLOWPAN_DISPATCH_FRAGN << 8) | uip_len); */ SET16(PACKETBUF_FRAG_PTR, PACKETBUF_FRAG_DISPATCH_SIZE, ((SICSLOWPAN_DISPATCH_FRAGN << 8) | uip_len)); - packetbuf_payload_len = (max_payload - packetbuf_hdr_len) & 0xfffffff8; + packetbuf_payload_len = (mac_max_payload - packetbuf_hdr_len) & 0xfffffff8; while(processed_ip_out_len < uip_len) { LOG_INFO("output: fragment "); PACKETBUF_FRAG_PTR[PACKETBUF_FRAG_OFFSET] = processed_ip_out_len >> 3; From eae1e7eb5a2532dea29efa6a7ed0a65befc35c2b Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 11 Apr 2018 04:19:03 -0700 Subject: [PATCH 027/129] sicslowpan: abort fragmentation in case the header does not fit the first fragment --- os/net/ipv6/sicslowpan.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index 5e4fd4f04..4e3e4e00c 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -1625,6 +1625,15 @@ output(const linkaddr_t *localdest) packetbuf_hdr_len += SICSLOWPAN_FRAG1_HDR_LEN; packetbuf_payload_len = (mac_max_payload - packetbuf_hdr_len) & 0xfffffff8; LOG_INFO_("(len %d, tag %d)\n", packetbuf_payload_len, frag_tag); + + if(packetbuf_payload_len < 0) { + /* The current implementation requires that all headers fit in the first + * fragment. Here is a corner case where the header did fit packetbuf + * but do no longer fit after truncating for a length multiple of 8. */ + LOG_WARN("compressed header does not fit first fragment\n"); + return 0; + } + memcpy(packetbuf_ptr + packetbuf_hdr_len, (uint8_t *)UIP_IP_BUF + uncomp_hdr_len, packetbuf_payload_len); packetbuf_set_datalen(packetbuf_payload_len + packetbuf_hdr_len); From 8f3376691fc76ad818df1cd3804c3a9c8df82a7d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 11 Apr 2018 04:20:39 -0700 Subject: [PATCH 028/129] RPL Lite: fix handling of max rank on 16-bit platforms --- os/net/routing/rpl-lite/rpl-neighbor.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-neighbor.c b/os/net/routing/rpl-lite/rpl-neighbor.c index d6a545e13..8afa2440f 100644 --- a/os/net/routing/rpl-lite/rpl-neighbor.c +++ b/os/net/routing/rpl-lite/rpl-neighbor.c @@ -63,6 +63,18 @@ static rpl_nbr_t * best_parent(int fresh_only); /* Per-neighbor RPL information */ NBR_TABLE_GLOBAL(rpl_nbr_t, rpl_neighbors); +/*---------------------------------------------------------------------------*/ +static int +max_acceptable_rank(void) +{ + if(curr_instance.max_rankinc == 0) { + /* There is no max rank increment */ + return RPL_INFINITE_RANK; + } else { + /* Make sure not to exceed RPL_INFINITE_RANK */ + return MIN((uint32_t)curr_instance.dag.lowest_rank + curr_instance.max_rankinc, RPL_INFINITE_RANK); + } +} /*---------------------------------------------------------------------------*/ /* As per RFC 6550, section 8.2.2.4 */ static int @@ -70,8 +82,7 @@ acceptable_rank(rpl_rank_t rank) { return rank != RPL_INFINITE_RANK && rank >= ROOT_RANK - && ((curr_instance.max_rankinc == 0) || - rank <= curr_instance.dag.lowest_rank + curr_instance.max_rankinc); + && rank <= max_acceptable_rank(); } /*---------------------------------------------------------------------------*/ void @@ -89,7 +100,7 @@ rpl_neighbor_print_list(const char *str) LOG_INFO_(", DAG state: %s, MOP %u OCP %u rank %u max-rank %u, dioint %u, nbr count %u (%s)\n", rpl_dag_state_to_str(curr_instance.dag.state), curr_instance.mop, curr_instance.of->ocp, curr_rank, - curr_instance.max_rankinc != 0 ? curr_instance.dag.lowest_rank + curr_instance.max_rankinc : 0xffff, + max_acceptable_rank(), curr_dio_interval, rpl_neighbor_count(), str); while(nbr != NULL) { const struct link_stats *stats = rpl_neighbor_get_link_stats(nbr); From f9c91ce5275b4db0f8e2419c55b83a2cfa16443d Mon Sep 17 00:00:00 2001 From: "carlosgp143@gmail.com" Date: Thu, 12 Apr 2018 13:39:37 +0200 Subject: [PATCH 029/129] Changed RPL_LEAF_ONLY flag to a runtime flag with getter and setter --- os/net/routing/rpl-lite/rpl-conf.h | 6 +-- os/net/routing/rpl-lite/rpl-icmp6.c | 72 ++++++++++++++-------------- os/net/routing/rpl-lite/rpl-timers.c | 10 ++-- os/net/routing/rpl-lite/rpl.c | 13 +++++ os/net/routing/rpl-lite/rpl.h | 14 ++++++ 5 files changed, 71 insertions(+), 44 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-conf.h b/os/net/routing/rpl-lite/rpl-conf.h index a3693f8b9..8d2f4b7b9 100644 --- a/os/net/routing/rpl-lite/rpl-conf.h +++ b/os/net/routing/rpl-lite/rpl-conf.h @@ -185,10 +185,10 @@ * This value decides if this node must stay as a leaf or not * as allowed by draft-ietf-roll-rpl-19#section-8.5 */ -#ifdef RPL_CONF_LEAF_ONLY -#define RPL_LEAF_ONLY RPL_CONF_LEAF_ONLY +#ifdef RPL_CONF_DEFAULT_LEAF_ONLY +#define RPL_DEFAULT_LEAF_ONLY RPL_CONF_DEFAULT_LEAF_ONLY #else -#define RPL_LEAF_ONLY 0 +#define RPL_DEFAULT_LEAF_ONLY 0 #endif /******************************************************************************/ diff --git a/os/net/routing/rpl-lite/rpl-icmp6.c b/os/net/routing/rpl-lite/rpl-icmp6.c index 1e4a50423..be5ea2948 100644 --- a/os/net/routing/rpl-lite/rpl-icmp6.c +++ b/os/net/routing/rpl-lite/rpl-icmp6.c @@ -342,14 +342,14 @@ rpl_icmp6_dio_output(uip_ipaddr_t *uc_addr) /* Make sure we're up-to-date before sending data out */ rpl_dag_update_state(); -#if RPL_LEAF_ONLY - /* In leaf mode, we only send DIO messages as unicasts in response to - unicast DIS messages. */ - if(uc_addr == NULL) { - /* Do not send multicast DIO in leaf mode */ - return; + if(rpl_get_leaf_only()) { + /* In leaf mode, we only send DIO messages as unicasts in response to + unicast DIS messages. */ + if(uc_addr == NULL) { + /* Do not send multicast DIO in leaf mode */ + return; + } } -#endif /* RPL_LEAF_ONLY */ /* DAG Information Object */ pos = 0; @@ -358,11 +358,11 @@ rpl_icmp6_dio_output(uip_ipaddr_t *uc_addr) buffer[pos++] = curr_instance.instance_id; buffer[pos++] = curr_instance.dag.version; -#if RPL_LEAF_ONLY - set16(buffer, pos, RPL_INFINITE_RANK); -#else /* RPL_LEAF_ONLY */ - set16(buffer, pos, curr_instance.dag.rank); -#endif /* RPL_LEAF_ONLY */ + if(rpl_get_leaf_only()) { + set16(buffer, pos, RPL_INFINITE_RANK); + } else { + set16(buffer, pos, curr_instance.dag.rank); + } pos += 2; buffer[pos] = 0; @@ -383,29 +383,29 @@ rpl_icmp6_dio_output(uip_ipaddr_t *uc_addr) memcpy(buffer + pos, &curr_instance.dag.dag_id, sizeof(curr_instance.dag.dag_id)); pos += 16; -#if !RPL_LEAF_ONLY - if(curr_instance.mc.type != RPL_DAG_MC_NONE) { - buffer[pos++] = RPL_OPTION_DAG_METRIC_CONTAINER; - buffer[pos++] = 6; - buffer[pos++] = curr_instance.mc.type; - buffer[pos++] = curr_instance.mc.flags >> 1; - buffer[pos] = (curr_instance.mc.flags & 1) << 7; - buffer[pos++] |= (curr_instance.mc.aggr << 4) | curr_instance.mc.prec; - if(curr_instance.mc.type == RPL_DAG_MC_ETX) { - buffer[pos++] = 2; - set16(buffer, pos, curr_instance.mc.obj.etx); - pos += 2; - } else if(curr_instance.mc.type == RPL_DAG_MC_ENERGY) { - buffer[pos++] = 2; - buffer[pos++] = curr_instance.mc.obj.energy.flags; - buffer[pos++] = curr_instance.mc.obj.energy.energy_est; - } else { - LOG_ERR("unable to send DIO because of unsupported DAG MC type %u\n", - (unsigned)curr_instance.mc.type); - return; + if(!rpl_get_leaf_only()) { + if(curr_instance.mc.type != RPL_DAG_MC_NONE) { + buffer[pos++] = RPL_OPTION_DAG_METRIC_CONTAINER; + buffer[pos++] = 6; + buffer[pos++] = curr_instance.mc.type; + buffer[pos++] = curr_instance.mc.flags >> 1; + buffer[pos] = (curr_instance.mc.flags & 1) << 7; + buffer[pos++] |= (curr_instance.mc.aggr << 4) | curr_instance.mc.prec; + if(curr_instance.mc.type == RPL_DAG_MC_ETX) { + buffer[pos++] = 2; + set16(buffer, pos, curr_instance.mc.obj.etx); + pos += 2; + } else if(curr_instance.mc.type == RPL_DAG_MC_ENERGY) { + buffer[pos++] = 2; + buffer[pos++] = curr_instance.mc.obj.energy.flags; + buffer[pos++] = curr_instance.mc.obj.energy.energy_est; + } else { + LOG_ERR("unable to send DIO because of unsupported DAG MC type %u\n", + (unsigned)curr_instance.mc.type); + return; + } } } -#endif /* !RPL_LEAF_ONLY */ /* Always add a DAG configuration option. */ buffer[pos++] = RPL_OPTION_DAG_CONF; @@ -442,9 +442,9 @@ rpl_icmp6_dio_output(uip_ipaddr_t *uc_addr) pos += 16; } -#if !RPL_LEAF_ONLY - addr = addr != NULL ? addr : &rpl_multicast_addr; -#endif /* RPL_LEAF_ONLY */ + if(!rpl_get_leaf_only()) { + addr = addr != NULL ? addr : &rpl_multicast_addr; + } LOG_INFO("sending a %s-DIO with rank %u to ", uc_addr != NULL ? "unicast" : "multicast", diff --git a/os/net/routing/rpl-lite/rpl-timers.c b/os/net/routing/rpl-lite/rpl-timers.c index f7a50b858..80a24fe66 100644 --- a/os/net/routing/rpl-lite/rpl-timers.c +++ b/os/net/routing/rpl-lite/rpl-timers.c @@ -150,11 +150,11 @@ rpl_timers_dio_reset(const char *str) { if(rpl_dag_ready_to_advertise()) { LOG_INFO("reset DIO timer (%s)\n", str); -#if !RPL_LEAF_ONLY - curr_instance.dag.dio_counter = 0; - curr_instance.dag.dio_intcurrent = curr_instance.dio_intmin; - new_dio_interval(); -#endif /* RPL_LEAF_ONLY */ + if(!rpl_get_leaf_only()) { + curr_instance.dag.dio_counter = 0; + curr_instance.dag.dio_intcurrent = curr_instance.dio_intmin; + new_dio_interval(); + } } } /*---------------------------------------------------------------------------*/ diff --git a/os/net/routing/rpl-lite/rpl.c b/os/net/routing/rpl-lite/rpl.c index acfe94c37..fd93b40e8 100644 --- a/os/net/routing/rpl-lite/rpl.c +++ b/os/net/routing/rpl-lite/rpl.c @@ -50,6 +50,7 @@ #define LOG_LEVEL LOG_LEVEL_RPL uip_ipaddr_t rpl_multicast_addr; +static uint8_t rpl_leaf_only = RPL_DEFAULT_LEAF_ONLY; /*---------------------------------------------------------------------------*/ int @@ -223,6 +224,18 @@ drop_route(uip_ds6_route_t *route) /* Do nothing. RPL-lite only supports non-storing mode, i.e. no routes */ } /*---------------------------------------------------------------------------*/ +void +rpl_set_leaf_only(uint8_t value) +{ + rpl_leaf_only = value; +} +/*---------------------------------------------------------------------------*/ +uint8_t +rpl_get_leaf_only(void) +{ + return rpl_leaf_only; +} +/*---------------------------------------------------------------------------*/ const struct routing_driver rpl_lite_driver = { "RPL Lite", init, diff --git a/os/net/routing/rpl-lite/rpl.h b/os/net/routing/rpl-lite/rpl.h index 25ac3863e..e39c825c4 100644 --- a/os/net/routing/rpl-lite/rpl.h +++ b/os/net/routing/rpl-lite/rpl.h @@ -133,6 +133,20 @@ int rpl_lollipop_greater_than(int a, int b); */ void rpl_refresh_routes(const char *str); +/** + * Changes the value of the rpl_leaf_only flag, which determines if a node acts + * only as a leaf in the network + * + * \param value the value to set: 0-disable, 1-enable + */ +void rpl_set_leaf_only(uint8_t value); + +/** + * Get the value of the rpl_leaf_only flag + * + * \return The value of the rpl_leaf_only flag + */ +uint8_t rpl_get_leaf_only(void); /** @} */ #endif /* RPL_H */ From 02aebac0d71a2d842b68c73520e2b9402a439a36 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 02:23:49 -0700 Subject: [PATCH 030/129] Viewconf: moving PANID up --- tools/viewconf.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/viewconf.c b/tools/viewconf.c index 5e6ee3d5e..4e7d4b497 100644 --- a/tools/viewconf.c +++ b/tools/viewconf.c @@ -16,18 +16,18 @@ ##### "CONTIKI_VERSION_STRING": ________________ == CONTIKI_VERSION_STRING -#ifdef IEEE802154_CONF_PANID -##### "IEEE802154_CONF_PANID":__________________ == IEEE802154_CONF_PANID -#else -##### "IEEE802154_CONF_PANID":__________________ == IEEE802154_PANID -#endif - #ifdef FRAME802154_CONF_VERSION ##### "FRAME802154_CONF_VERSION":_______________ == FRAME802154_CONF_VERSION #else ##### "FRAME802154_CONF_VERSION":_______________ == FRAME802154_VERSION #endif +#ifdef IEEE802154_CONF_PANID +##### "IEEE802154_CONF_PANID":__________________ == IEEE802154_CONF_PANID +#else +##### "IEEE802154_CONF_PANID":__________________ == IEEE802154_PANID +#endif + #if MAC_CONF_WITH_TSCH #ifdef TSCH_CONF_DEFAULT_HOPPING_SEQUENCE From 15a06b85bc8981d65fa527ba65a9170145234263 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 02:26:48 -0700 Subject: [PATCH 031/129] Added flag for 802.15.4 default channel --- os/contiki-default-conf.h | 10 ++++++++++ os/net/mac/mac.h | 8 ++++++++ tools/viewconf.c | 6 +++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/os/contiki-default-conf.h b/os/contiki-default-conf.h index 8ec1a41f7..f8fbc9933 100644 --- a/os/contiki-default-conf.h +++ b/os/contiki-default-conf.h @@ -41,6 +41,16 @@ #define IEEE802154_CONF_PANID 0xabcd #endif /* IEEE802154_CONF_PANID */ +/* IEEE802154_CONF_DEFAULT_CHANNEL defines the default channel for IEEE 802.15.4 + * networks, for MAC layers without a channel selection or channel hopping + * mechanism. Current 802.15.4 MAC layers: + * - CSMA: uses IEEE802154_CONF_DEFAULT_CHANNEL + * - TSCH: uses its own TSCH_DEFAULT_HOPPING_SEQUENCE instead + */ +#ifndef IEEE802154_CONF_DEFAULT_CHANNEL +#define IEEE802154_CONF_DEFAULT_CHANNEL 26 +#endif /* IEEE802154_CONF_DEF_CHANNEL */ + /* QUEUEBUF_CONF_NUM specifies the number of queue buffers. Queue buffers are used throughout the Contiki netstack but the configuration option can be tweaked to save memory. Performance can diff --git a/os/net/mac/mac.h b/os/net/mac/mac.h index ce68d46c7..4f2a75b15 100644 --- a/os/net/mac/mac.h +++ b/os/net/mac/mac.h @@ -43,6 +43,14 @@ #include "contiki.h" #include "dev/radio.h" +/** + *\brief The default channel for IEEE 802.15.4 networks. + */ +#ifdef IEEE802154_CONF_DEFAULT_CHANNEL +#define IEEE802154_DEFAULT_CHANNEL IEEE802154_CONF_DEFAULT_CHANNEL +#else /* IEEE802154_CONF_DEFAULT_CHANNEL */ +#define IEEE802154_DEFAULT_CHANNEL 26 +#endif /* IEEE802154_CONF_DEFAULT_CHANNEL */ typedef void (* mac_callback_t)(void *ptr, int status, int transmissions); diff --git a/tools/viewconf.c b/tools/viewconf.c index 4e7d4b497..678663ee1 100644 --- a/tools/viewconf.c +++ b/tools/viewconf.c @@ -68,10 +68,10 @@ #else /* MAC_CONF_WITH_TSCH */ -#ifdef RF_CHANNEL -##### "RF_CHANNEL": ____________________________ == RF_CHANNEL +#ifdef IEEE802154_CONF_DEFAULT_CHANNEL +##### "IEEE802154_CONF_DEFAULT_CHANNEL": _______ == IEEE802154_CONF_DEFAULT_CHANNEL #else -##### "RF_CHANNEL": ____________________________ >< +##### "IEEE802154_CONF_DEFAULT_CHANNEL": _______ -> IEEE802154_DEFAULT_CHANNEL #endif #endif /*MAC_CONF_WITH_TSCH */ From 0b2ea0d8108ab55877a3b78d1b705ac398fb7154 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 02:27:17 -0700 Subject: [PATCH 032/129] cc2538-rf: use IEEE802154_DEFAULT_CHANNEL --- arch/cpu/cc2538/cc2538-conf.h | 8 -------- arch/cpu/cc2538/dev/cc2538-rf.c | 2 +- arch/cpu/cc2538/dev/cc2538-rf.h | 6 ------ arch/platform/cc2538dk/platform.c | 2 +- arch/platform/openmote-cc2538/platform.c | 2 +- arch/platform/zoul/platform.c | 2 +- 6 files changed, 4 insertions(+), 18 deletions(-) diff --git a/arch/cpu/cc2538/cc2538-conf.h b/arch/cpu/cc2538/cc2538-conf.h index 725f95439..d34c3dee5 100644 --- a/arch/cpu/cc2538/cc2538-conf.h +++ b/arch/cpu/cc2538/cc2538-conf.h @@ -219,14 +219,6 @@ */ /* RF Config */ -#ifdef RF_CHANNEL -#define CC2538_RF_CONF_CHANNEL RF_CHANNEL -#endif - -#ifndef CC2538_RF_CONF_CHANNEL -#define CC2538_RF_CONF_CHANNEL 26 -#endif /* CC2538_RF_CONF_CHANNEL */ - #ifndef CC2538_RF_CONF_AUTOACK #define CC2538_RF_CONF_AUTOACK 1 /**< RF H/W generates ACKs */ #endif /* CC2538_CONF_AUTOACK */ diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index 5e6661b3e..f33e87131 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -113,7 +113,7 @@ static int8_t rssi; static uint8_t crc_corr; /*---------------------------------------------------------------------------*/ static uint8_t rf_flags; -static uint8_t rf_channel = CC2538_RF_CHANNEL; +static uint8_t rf_channel = IEEE802154_DEFAULT_CHANNEL; static int on(void); static int off(void); diff --git a/arch/cpu/cc2538/dev/cc2538-rf.h b/arch/cpu/cc2538/dev/cc2538-rf.h index 87fef3a59..b89738436 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.h +++ b/arch/cpu/cc2538/dev/cc2538-rf.h @@ -74,12 +74,6 @@ #define CC2538_RF_CCA_THRES CC2538_RF_CCA_THRES_USER_GUIDE #endif /* CC2538_RF_CONF_CCA_THRES */ -#ifdef CC2538_RF_CONF_CHANNEL -#define CC2538_RF_CHANNEL CC2538_RF_CONF_CHANNEL -#else -#define CC2538_RF_CHANNEL 18 -#endif /* CC2538_RF_CONF_CHANNEL */ - #ifdef CC2538_RF_CONF_AUTOACK #define CC2538_RF_AUTOACK CC2538_RF_CONF_AUTOACK #else diff --git a/arch/platform/cc2538dk/platform.c b/arch/platform/cc2538dk/platform.c index bf945bfdd..2a3ca21ed 100644 --- a/arch/platform/cc2538dk/platform.c +++ b/arch/platform/cc2538dk/platform.c @@ -106,7 +106,7 @@ set_rf_params(void) NETSTACK_RADIO.set_value(RADIO_PARAM_PAN_ID, IEEE802154_PANID); NETSTACK_RADIO.set_value(RADIO_PARAM_16BIT_ADDR, short_addr); - NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, CC2538_RF_CHANNEL); + NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, IEEE802154_DEFAULT_CHANNEL); NETSTACK_RADIO.set_object(RADIO_PARAM_64BIT_ADDR, ext_addr, 8); } /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/openmote-cc2538/platform.c b/arch/platform/openmote-cc2538/platform.c index c226785c6..4656d2332 100644 --- a/arch/platform/openmote-cc2538/platform.c +++ b/arch/platform/openmote-cc2538/platform.c @@ -115,7 +115,7 @@ set_rf_params(void) NETSTACK_RADIO.set_value(RADIO_PARAM_PAN_ID, IEEE802154_PANID); NETSTACK_RADIO.set_value(RADIO_PARAM_16BIT_ADDR, short_addr); - NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, CC2538_RF_CHANNEL); + NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, IEEE802154_DEFAULT_CHANNEL); NETSTACK_RADIO.set_object(RADIO_PARAM_64BIT_ADDR, ext_addr, 8); } /*---------------------------------------------------------------------------*/ diff --git a/arch/platform/zoul/platform.c b/arch/platform/zoul/platform.c index 8cce149ee..703f0e521 100644 --- a/arch/platform/zoul/platform.c +++ b/arch/platform/zoul/platform.c @@ -171,7 +171,7 @@ set_rf_params(void) NETSTACK_RADIO.set_value(RADIO_PARAM_PAN_ID, IEEE802154_PANID); NETSTACK_RADIO.set_value(RADIO_PARAM_16BIT_ADDR, short_addr); - NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, CC2538_RF_CHANNEL); + NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, IEEE802154_DEFAULT_CHANNEL); NETSTACK_RADIO.set_object(RADIO_PARAM_64BIT_ADDR, ext_addr, 8); } /*---------------------------------------------------------------------------*/ From 24e24b8edcc658e6098904b6fbdaaf12b46c9fc6 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Thu, 12 Apr 2018 17:34:35 +0200 Subject: [PATCH 033/129] coap: added check for block offset overflow in block2 requests. The block offset is stored in a signed variable in calls to CoAP handlers and too large block offsets will overflow into negative values. Thanks to Bruno Melo for reporting this issue. --- os/net/app-layer/coap/coap-engine.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/os/net/app-layer/coap/coap-engine.c b/os/net/app-layer/coap/coap-engine.c index fb85b5b15..cbfa70ee9 100644 --- a/os/net/app-layer/coap/coap-engine.c +++ b/os/net/app-layer/coap/coap-engine.c @@ -199,10 +199,18 @@ coap_receive(const coap_endpoint_t *src, new_offset = block_offset; } - /* call CoAP framework and check if found and allowed */ - status = call_service(message, response, - transaction->message + COAP_MAX_HEADER_SIZE, - block_size, &new_offset); + if(new_offset < 0) { + LOG_DBG("Blockwise: block request offset overflow\n"); + coap_status_code = BAD_OPTION_4_02; + coap_error_message = "BlockOutOfScope"; + status = COAP_HANDLER_STATUS_CONTINUE; + } else { + /* call CoAP framework and check if found and allowed */ + status = call_service(message, response, + transaction->message + COAP_MAX_HEADER_SIZE, + block_size, &new_offset); + } + if(status != COAP_HANDLER_STATUS_CONTINUE) { if(coap_status_code == NO_ERROR) { From fc8619608af1ca2766c57d2b4a00b61a26ae8608 Mon Sep 17 00:00:00 2001 From: Joakim Eriksson Date: Fri, 13 Apr 2018 14:27:01 +0200 Subject: [PATCH 034/129] fixed typo in comment. --- os/net/routing/rpl-lite/rpl-dag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index a2a18c59a..6fe58f273 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -401,7 +401,7 @@ process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio) if(dio->rank == ROOT_RANK) { /* Before returning, if the DIO was from the root, an old DAG versions * likely incidates a root reboot. Reset our DIO timer to make sure the - * root hears our version ASAP, and in trun triggers a global repair. */ + * root hears our version ASAP, and in turn triggers a global repair. */ rpl_timers_dio_reset("Heard old version from root"); } return; From 0df3c4fb90297d1e9e57f8e6f4cee409fb899b66 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 5 Apr 2018 05:35:27 -0700 Subject: [PATCH 035/129] CoAP: enable calling coap_get_payload with a NULL pointer --- os/net/app-layer/coap/coap.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/os/net/app-layer/coap/coap.c b/os/net/app-layer/coap/coap.c index 42a2d5cef..c28e2d8b5 100644 --- a/os/net/app-layer/coap/coap.c +++ b/os/net/app-layer/coap/coap.c @@ -1115,13 +1115,10 @@ coap_set_header_size1(coap_message_t *coap_pkt, uint32_t size) int coap_get_payload(coap_message_t *coap_pkt, const uint8_t **payload) { - if(coap_pkt->payload) { + if(payload != NULL) { *payload = coap_pkt->payload; - return coap_pkt->payload_len; - } else { - *payload = NULL; - return 0; } + return coap_pkt->payload != NULL ? coap_pkt->payload_len : 0; } int coap_set_payload(coap_message_t *coap_pkt, const void *payload, size_t length) From d3c37eb61bfbb450634b1add6b605d7f7f1fe56e Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:39:03 -0700 Subject: [PATCH 036/129] rpl_refresh_routes: log new DTSN rather than old one --- os/net/routing/rpl-lite/rpl-dag.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index 00ee1663e..6624c868a 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -183,14 +183,14 @@ void rpl_refresh_routes(const char *str) { if(rpl_dag_root_is_root()) { - LOG_WARN("incrementing DTSN (%s), current %u)\n", + /* Increment DTSN */ + RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out); + + LOG_WARN("incremented DTSN (%s), current %u\n", str, curr_instance.dtsn_out); if(LOG_INFO_ENABLED) { rpl_neighbor_print_list("Refresh routes (before)"); } - - /* Increment DTSN */ - RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out); } } /*---------------------------------------------------------------------------*/ From cdca6959ebe156b4fadf40c5c83563577be90de2 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:39:54 -0700 Subject: [PATCH 037/129] RPL global repair: log new version rather than old one. Re-init DTSN instead of incrementing it. Log format fixes. --- os/net/routing/rpl-lite/rpl-dag.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index 6624c868a..929c29314 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -198,15 +198,16 @@ void rpl_global_repair(const char *str) { if(rpl_dag_root_is_root()) { - LOG_WARN("initiating global repair (%s), version %u, rank %u)\n", + RPL_LOLLIPOP_INCREMENT(curr_instance.dag.version); /* New DAG version */ + curr_instance.dtsn_out = RPL_LOLLIPOP_INIT; /* Re-initialize DTSN */ + + LOG_WARN("initiating global repair (%s), version %u, rank %u\n", str, curr_instance.dag.version, curr_instance.dag.rank); if(LOG_INFO_ENABLED) { rpl_neighbor_print_list("Global repair (before)"); } - /* Initiate global repair */ - RPL_LOLLIPOP_INCREMENT(curr_instance.dag.version); /* New DAG version */ - RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out); /* Request new DAOs */ + /* Now do a local repair to disseminate the new version */ rpl_local_repair("Global repair"); } } @@ -215,8 +216,8 @@ static void global_repair_non_root(rpl_dio_t *dio) { if(!rpl_dag_root_is_root()) { - LOG_WARN("participating in global repair, version %u, rank %u)\n", - curr_instance.dag.version, curr_instance.dag.rank); + LOG_WARN("participating in global repair, version %u, rank %u\n", + dio->version, curr_instance.dag.rank); if(LOG_INFO_ENABLED) { rpl_neighbor_print_list("Global repair (before)"); } From 86ac0fba68cdb6c72a50ea404a7ad1f6026883fa Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:40:15 -0700 Subject: [PATCH 038/129] RPL global repair: stop all timers before re-initializing --- os/net/routing/rpl-lite/rpl-dag.c | 1 + 1 file changed, 1 insertion(+) diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index 929c29314..13c01d68d 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -222,6 +222,7 @@ global_repair_non_root(rpl_dio_t *dio) rpl_neighbor_print_list("Global repair (before)"); } /* Re-initialize configuration from DIO */ + rpl_timers_stop_dag_timers(); init_dag_from_dio(dio); rpl_local_repair("Global repair"); } From dd8bf5d60ac69559bd1a3874500a4edd506e75d7 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:40:39 -0700 Subject: [PATCH 039/129] RPL DTSN increment log: fix format, promote from INFO to WARN --- os/net/routing/rpl-lite/rpl-dag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/routing/rpl-lite/rpl-dag.c b/os/net/routing/rpl-lite/rpl-dag.c index 13c01d68d..5a9a160b6 100644 --- a/os/net/routing/rpl-lite/rpl-dag.c +++ b/os/net/routing/rpl-lite/rpl-dag.c @@ -453,7 +453,7 @@ process_dio_from_current_dag(uip_ipaddr_t *from, rpl_dio_t *dio) if(curr_instance.mop != RPL_MOP_NO_DOWNWARD_ROUTES) { if(nbr != NULL && nbr == curr_instance.dag.preferred_parent && rpl_lollipop_greater_than(dio->dtsn, last_dtsn)) { RPL_LOLLIPOP_INCREMENT(curr_instance.dtsn_out); - LOG_INFO("DTSN increment %u->%u, schedule new DAO with DTSN %u", + LOG_WARN("DTSN increment %u->%u, schedule new DAO with DTSN %u\n", last_dtsn, dio->dtsn, curr_instance.dtsn_out); rpl_timers_schedule_dao(); } From a49a5dc67544ab749bbe18f6ce1f555a468e619d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:41:06 -0700 Subject: [PATCH 040/129] RPL handle_proving_timer: fix defensive programming check --- os/net/routing/rpl-lite/rpl-timers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/routing/rpl-lite/rpl-timers.c b/os/net/routing/rpl-lite/rpl-timers.c index f7a50b858..6cd188f9d 100644 --- a/os/net/routing/rpl-lite/rpl-timers.c +++ b/os/net/routing/rpl-lite/rpl-timers.c @@ -435,7 +435,7 @@ handle_probing_timer(void *ptr) LOG_INFO_6ADDR(target_ipaddr); LOG_INFO_(" %s last tx %u min ago\n", curr_instance.dag.urgent_probing_target != NULL ? "(urgent)" : "", - probing_target != NULL ? + stats != NULL ? (unsigned)((clock_time() - stats->last_tx_time) / (60 * CLOCK_SECOND)) : 0 ); /* Send probe, e.g. unicast DIO or DIS */ From ebcb94186763854b1bf7189de47c735cfbb19930 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 6 Apr 2018 09:41:34 -0700 Subject: [PATCH 041/129] Shell command 'rpl_status': show last DTSN of current parent --- os/services/shell/shell-commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/services/shell/shell-commands.c b/os/services/shell/shell-commands.c index 46ee92fe5..7920fb086 100644 --- a/os/services/shell/shell-commands.c +++ b/os/services/shell/shell-commands.c @@ -174,7 +174,7 @@ PT_THREAD(cmd_rpl_status(struct pt *pt, shell_output_func output, char *args)) SHELL_OUTPUT(output, "-- State: %s\n", rpl_state_to_str(curr_instance.dag.state)); SHELL_OUTPUT(output, "-- Preferred parent: "); shell_output_6addr(output, rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent)); - SHELL_OUTPUT(output, "\n"); + SHELL_OUTPUT(output, " (last DTSN: %u)\n", curr_instance.dag.preferred_parent->dtsn); SHELL_OUTPUT(output, "-- Rank: %u\n", curr_instance.dag.rank); SHELL_OUTPUT(output, "-- Lowest rank: %u (%u)\n", curr_instance.dag.lowest_rank, curr_instance.max_rankinc); SHELL_OUTPUT(output, "-- DTSN out: %u\n", curr_instance.dtsn_out); From cc37c1a558972dbf930a1b087aa52de2dbc1ab83 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 5 Apr 2018 05:35:27 -0700 Subject: [PATCH 042/129] CoAP: enable calling coap_get_payload with a NULL pointer --- os/net/app-layer/coap/coap.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/os/net/app-layer/coap/coap.c b/os/net/app-layer/coap/coap.c index 42a2d5cef..c28e2d8b5 100644 --- a/os/net/app-layer/coap/coap.c +++ b/os/net/app-layer/coap/coap.c @@ -1115,13 +1115,10 @@ coap_set_header_size1(coap_message_t *coap_pkt, uint32_t size) int coap_get_payload(coap_message_t *coap_pkt, const uint8_t **payload) { - if(coap_pkt->payload) { + if(payload != NULL) { *payload = coap_pkt->payload; - return coap_pkt->payload_len; - } else { - *payload = NULL; - return 0; } + return coap_pkt->payload != NULL ? coap_pkt->payload_len : 0; } int coap_set_payload(coap_message_t *coap_pkt, const void *payload, size_t length) From 7a96a8f8a9225345fe0a9277b802a7c07e9cddc3 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 5 Apr 2018 02:17:05 -0700 Subject: [PATCH 043/129] CoAP: auto-initialize module --- examples/coap/coap-example-client.c | 3 --- examples/coap/coap-example-server.c | 5 +---- examples/coap/plugtest-server.c | 3 --- examples/ipso-objects/example-server.c | 3 --- .../platform-specific/cc26xx/cc26xx-web-demo/coap-server.c | 3 --- .../cc26xx/very-sleepy-demo/very-sleepy-demo.c | 2 -- .../jn516x/rpl/coap-dongle-node/dongle-node.c | 1 - .../jn516x/rpl/coap-dr1175-node/dr1175-node.c | 1 - .../jn516x/rpl/coap-dr1199-node/dr1199-node.c | 1 - .../jn516x/tsch/tx-power-verification/node/node.c | 1 - .../jn516x/tsch/uart1-test-node/uart1-test-node.c | 1 - .../nrf52dk/coap-demo/coap-client/coap-client.c | 3 --- .../nrf52dk/coap-demo/coap-server/coap-server.c | 2 -- os/contiki-main.c | 6 ++++++ os/net/app-layer/coap/module-macros.h | 1 + os/services/lwm2m/lwm2m-engine.c | 3 +++ 16 files changed, 11 insertions(+), 28 deletions(-) create mode 100644 os/net/app-layer/coap/module-macros.h diff --git a/examples/coap/coap-example-client.c b/examples/coap/coap-example-client.c index 27efbbf6e..3fe261cf7 100644 --- a/examples/coap/coap-example-client.c +++ b/examples/coap/coap-example-client.c @@ -92,9 +92,6 @@ PROCESS_THREAD(er_example_client, ev, data) coap_endpoint_parse(SERVER_EP, strlen(SERVER_EP), &server_ep); - /* receives all CoAP messages */ - coap_engine_init(); - etimer_set(&et, TOGGLE_INTERVAL * CLOCK_SECOND); #if PLATFORM_HAS_BUTTON diff --git a/examples/coap/coap-example-server.c b/examples/coap/coap-example-server.c index 41ea53744..272421d18 100644 --- a/examples/coap/coap-example-server.c +++ b/examples/coap/coap-example-server.c @@ -119,15 +119,12 @@ PROCESS_THREAD(er_example_server, ev, data) PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); PRINTF("CoAP max chunk: %u\n", COAP_MAX_CHUNK_SIZE); - /* Initialize the REST engine. */ - coap_engine_init(); - /* * Bind the resources to their Uri-Path. * WARNING: Activating twice only means alternate path, not two instances! * All static variables are the same for each URI path. */ - coap_activate_resource(&res_hello, "test/hello"); + coap_activate_resource(&res_hello, "test/hello"); coap_activate_resource(&res_mirror, "debug/mirror"); coap_activate_resource(&res_chunks, "test/chunks"); coap_activate_resource(&res_separate, "test/separate"); diff --git a/examples/coap/plugtest-server.c b/examples/coap/plugtest-server.c index 7ca53bc2d..2965692b5 100644 --- a/examples/coap/plugtest-server.c +++ b/examples/coap/plugtest-server.c @@ -94,9 +94,6 @@ PROCESS_THREAD(plugtest_server, ev, data) PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); PRINTF("REST max chunk: %u\n", REST_MAX_CHUNK_SIZE); - /* Initialize the REST engine. */ - coap_engine_init(); - /* Activate the application-specific resources. */ coap_activate_resource(&res_plugtest_test, "test"); coap_activate_resource(&res_plugtest_validate, "validate"); diff --git a/examples/ipso-objects/example-server.c b/examples/ipso-objects/example-server.c index 4eac38f69..658c8b24e 100644 --- a/examples/ipso-objects/example-server.c +++ b/examples/ipso-objects/example-server.c @@ -267,9 +267,6 @@ PROCESS_THREAD(router_process, ev, data) PROCESS_PAUSE(); - /* receives all CoAP messages */ - coap_engine_init(); - setup_network(); while(1) { diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/coap-server.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/coap-server.c index 54289f102..37b9a295d 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/coap-server.c +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/coap-server.c @@ -133,9 +133,6 @@ PROCESS_THREAD(coap_server_process, ev, data) printf("CC26XX CoAP Server\n"); - /* Initialize the REST engine. */ - coap_engine_init(); - coap_activate_resource(&res_batmon_temp, "sen/batmon/temp"); coap_activate_resource(&res_batmon_volt, "sen/batmon/voltage"); diff --git a/examples/platform-specific/cc26xx/very-sleepy-demo/very-sleepy-demo.c b/examples/platform-specific/cc26xx/very-sleepy-demo/very-sleepy-demo.c index cac8033b7..ebd55712b 100644 --- a/examples/platform-specific/cc26xx/very-sleepy-demo/very-sleepy-demo.c +++ b/examples/platform-specific/cc26xx/very-sleepy-demo/very-sleepy-demo.c @@ -344,8 +344,6 @@ PROCESS_THREAD(very_sleepy_demo_process, ev, data) event_new_config = process_alloc_event(); - coap_engine_init(); - readings_resource.flags += IS_OBSERVABLE; coap_activate_resource(&readings_resource, "sen/readings"); coap_activate_resource(&very_sleepy_conf, "very_sleepy_config"); diff --git a/examples/platform-specific/jn516x/rpl/coap-dongle-node/dongle-node.c b/examples/platform-specific/jn516x/rpl/coap-dongle-node/dongle-node.c index 2fb2d7761..9c7cbb7aa 100644 --- a/examples/platform-specific/jn516x/rpl/coap-dongle-node/dongle-node.c +++ b/examples/platform-specific/jn516x/rpl/coap-dongle-node/dongle-node.c @@ -135,7 +135,6 @@ PROCESS_THREAD(start_app, ev, data) NETSTACK_MAC.on(); printf("Starting RPL node\n"); - coap_engine_init(); coap_activate_resource(&resource_led_toggle, "Dongle/LED-toggle"); PROCESS_END(); diff --git a/examples/platform-specific/jn516x/rpl/coap-dr1175-node/dr1175-node.c b/examples/platform-specific/jn516x/rpl/coap-dr1175-node/dr1175-node.c index 443cf4fbe..4a8432099 100644 --- a/examples/platform-specific/jn516x/rpl/coap-dr1175-node/dr1175-node.c +++ b/examples/platform-specific/jn516x/rpl/coap-dr1175-node/dr1175-node.c @@ -355,7 +355,6 @@ PROCESS_THREAD(start_app, ev, data) NETSTACK_MAC.on(); printf("Starting RPL node\n"); - coap_engine_init(); coap_activate_resource(&resource_light_sensor_value, "DR1175/LightSensor/Value"); coap_activate_resource(&resource_light_sensor_unit, "DR1175/LightSensor/Unit"); coap_activate_resource(&resource_temperature_unit, "DR1175/Temperature/Unit"); diff --git a/examples/platform-specific/jn516x/rpl/coap-dr1199-node/dr1199-node.c b/examples/platform-specific/jn516x/rpl/coap-dr1199-node/dr1199-node.c index d341170ad..d493636b5 100644 --- a/examples/platform-specific/jn516x/rpl/coap-dr1199-node/dr1199-node.c +++ b/examples/platform-specific/jn516x/rpl/coap-dr1199-node/dr1199-node.c @@ -356,7 +356,6 @@ PROCESS_THREAD(start_app, ev, data) NETSTACK_MAC.on(); printf("Starting RPL node\n"); - coap_engine_init(); coap_activate_resource(&resource_switch_sw1, "DR1199/Switch/SW1"); coap_activate_resource(&resource_switch_sw2, "DR1199/Switch/SW2"); coap_activate_resource(&resource_switch_sw3, "DR1199/Switch/SW3"); diff --git a/examples/platform-specific/jn516x/tsch/tx-power-verification/node/node.c b/examples/platform-specific/jn516x/tsch/tx-power-verification/node/node.c index 995dc3304..2230f4831 100644 --- a/examples/platform-specific/jn516x/tsch/tx-power-verification/node/node.c +++ b/examples/platform-specific/jn516x/tsch/tx-power-verification/node/node.c @@ -110,7 +110,6 @@ PROCESS_THREAD(start_app, ev, data) NETSTACK_MAC.on(); printf("Starting RPL node\n"); - coap_engine_init(); coap_activate_resource(&resource_set_tx_power, "Set-TX-Power"); coap_activate_resource(&resource_get_tx_power, "Get-TX-Power"); diff --git a/examples/platform-specific/jn516x/tsch/uart1-test-node/uart1-test-node.c b/examples/platform-specific/jn516x/tsch/uart1-test-node/uart1-test-node.c index dd647fa21..8759e8307 100644 --- a/examples/platform-specific/jn516x/tsch/uart1-test-node/uart1-test-node.c +++ b/examples/platform-specific/jn516x/tsch/uart1-test-node/uart1-test-node.c @@ -151,7 +151,6 @@ PROCESS_THREAD(start_app, ev, data) NETSTACK_MAC.on(); printf("Starting RPL node\n"); - coap_engine_init(); coap_activate_resource(&resource_coap_rx_uart1, "UART1-RX"); coap_activate_resource(&resource_coap_tx_uart1, "UART1-TX"); diff --git a/examples/platform-specific/nrf52dk/coap-demo/coap-client/coap-client.c b/examples/platform-specific/nrf52dk/coap-demo/coap-client/coap-client.c index 4effcc876..916c06603 100644 --- a/examples/platform-specific/nrf52dk/coap-demo/coap-client/coap-client.c +++ b/examples/platform-specific/nrf52dk/coap-demo/coap-client/coap-client.c @@ -148,9 +148,6 @@ PROCESS_THREAD(er_example_observe_client, ev, data) static coap_endpoint_t server_endpoint; coap_endpoint_parse(SERVER_IPV6_EP, strlen(SERVER_IPV6_EP), &server_endpoint); - /* receives all CoAP messages */ - coap_engine_init(); - #if PLATFORM_HAS_BUTTON SENSORS_ACTIVATE(button_1); SENSORS_ACTIVATE(button_2); diff --git a/examples/platform-specific/nrf52dk/coap-demo/coap-server/coap-server.c b/examples/platform-specific/nrf52dk/coap-demo/coap-server/coap-server.c index 6b4025cd3..584f54318 100644 --- a/examples/platform-specific/nrf52dk/coap-demo/coap-server/coap-server.c +++ b/examples/platform-specific/nrf52dk/coap-demo/coap-server/coap-server.c @@ -103,8 +103,6 @@ PROCESS_THREAD(er_example_server, ev, data) print_local_addresses(); - /* Initialize the REST engine. */ - coap_engine_init(); coap_activate_resource(&res_led3, "lights/led3"); SENSORS_ACTIVATE(button_1); diff --git a/os/contiki-main.c b/os/contiki-main.c index 234b759ee..0e29a2728 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -47,6 +47,7 @@ #include "sys/stack-check.h" #include "dev/watchdog.h" +#include "net/app-layer/coap/coap-engine.h" #include "services/rpl-border-router/rpl-border-router.h" #include "services/orchestra/orchestra.h" #include "services/shell/serial-shell.h" @@ -126,6 +127,11 @@ main(void) LOG_DBG("With Shell\n"); #endif /* BUILD_WITH_SHELL */ +#if BUILD_WITH_COAP + coap_engine_init(); + LOG_DBG("With CoAP\n"); +#endif /* BUILD_WITH_SHELL */ + autostart_start(autostart_processes); watchdog_start(); diff --git a/os/net/app-layer/coap/module-macros.h b/os/net/app-layer/coap/module-macros.h new file mode 100644 index 000000000..053040e50 --- /dev/null +++ b/os/net/app-layer/coap/module-macros.h @@ -0,0 +1 @@ +#define BUILD_WITH_COAP 1 diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index b96674215..d40154bfa 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -543,6 +543,9 @@ lwm2m_engine_init(void) #endif /* LWM2M_ENGINE_CLIENT_ENDPOINT_NAME */ + /* Initialize CoAP engine. Contiki-NG already does that from the main, + * but for standalone use of lwm2m, this is required here. coap_engine_init() + * checks for double-initialization and can be called twice safely. */ coap_engine_init(); /* Register the CoAP handler for lightweight object handling */ From 02b96f74746baee98ef2063093eba5d11fbda510 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 06:49:28 -0700 Subject: [PATCH 044/129] Remove warning in case coap_engine_init is called twice --- os/net/app-layer/coap/coap-engine.c | 1 - 1 file changed, 1 deletion(-) diff --git a/os/net/app-layer/coap/coap-engine.c b/os/net/app-layer/coap/coap-engine.c index fb85b5b15..816393ec0 100644 --- a/os/net/app-layer/coap/coap-engine.c +++ b/os/net/app-layer/coap/coap-engine.c @@ -363,7 +363,6 @@ coap_engine_init(void) { /* avoid initializing twice */ if(is_initialized) { - LOG_DBG("already running - double initialization?\n"); return; } is_initialized = 1; From 8bc3a7388e1707cf6ddd5b694d397685aabb865f Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 02:29:56 -0700 Subject: [PATCH 045/129] cc26xx and cc13xx: use IEEE802154_DEFAULT_CHANNEL --- arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h | 15 ++++----------- arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c | 2 +- arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c | 2 +- arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h | 7 ------- arch/platform/srf06-cc26xx/platform.c | 2 +- .../cc26xx/cc26xx-web-demo/project-conf.h | 2 +- examples/platform-specific/cc26xx/project-conf.h | 2 +- .../cc26xx/very-sleepy-demo/project-conf.h | 2 +- 8 files changed, 10 insertions(+), 24 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h index 83519f795..9c00a1823 100644 --- a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h @@ -54,14 +54,6 @@ #define CC2650_FAST_RADIO_STARTUP (MAC_CONF_WITH_TSCH) #endif -#ifdef RF_CHANNEL -#define RF_CORE_CONF_CHANNEL RF_CHANNEL -#endif - -#ifndef RF_CORE_CONF_CHANNEL -#define RF_CORE_CONF_CHANNEL 25 -#endif - /* Number of Prop Mode RX buffers */ #ifndef PROP_MODE_CONF_RX_BUF_CNT #define PROP_MODE_CONF_RX_BUF_CNT 4 @@ -81,9 +73,10 @@ #if CC13XX_CONF_PROP_MODE #define NETSTACK_CONF_RADIO prop_mode_driver -#ifndef RF_CORE_CONF_CHANNEL -#define RF_CORE_CONF_CHANNEL 0 -#endif +/* Channels count from 0 upwards in IEEE 802.15.4g */ +#ifndef IEEE802154_CONF_DEFAULT_CHANNEL +#define IEEE802154_CONF_DEFAULT_CHANNEL 0 +#endif /* IEEE802154_CONF_DEFAULT_CHANNEL */ #define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 400) #define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c b/arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c index a5479a4ee..3516147b5 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/ieee-mode.c @@ -610,7 +610,7 @@ init_rf_params(void) cmd->startTime = 0x00000000; cmd->startTrigger.triggerType = TRIG_NOW; cmd->condition.rule = COND_NEVER; - cmd->channel = RF_CORE_CHANNEL; + cmd->channel = IEEE802154_DEFAULT_CHANNEL; cmd->rxConfig.bAutoFlushCrc = 1; cmd->rxConfig.bAutoFlushIgn = 0; diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c b/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c index f9f49e9a0..f4e7f66e7 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c +++ b/arch/cpu/cc26xx-cc13xx/rf-core/prop-mode.c @@ -629,7 +629,7 @@ init(void) smartrf_settings_cmd_prop_rx_adv.pQueue = &rx_data_queue; smartrf_settings_cmd_prop_rx_adv.pOutput = (uint8_t *)&rx_stats; - set_channel(RF_CORE_CHANNEL); + set_channel(IEEE802154_DEFAULT_CHANNEL); if(on() != RF_CORE_CMD_OK) { PRINTF("init: on() failed\n"); diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h index 3264cfc01..ac48bc52a 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/rf-core.h @@ -57,13 +57,6 @@ #include #include /*---------------------------------------------------------------------------*/ -/* The channel to use in IEEE or prop mode. */ -#ifdef RF_CORE_CONF_CHANNEL -#define RF_CORE_CHANNEL RF_CORE_CONF_CHANNEL -#else -#define RF_CORE_CHANNEL 25 -#endif /* RF_CORE_CONF_IEEE_MODE_CHANNEL */ -/*---------------------------------------------------------------------------*/ #define RF_CORE_FRONT_END_MODE_DIFFERENTIAL 0 #define RF_CORE_FRONT_END_MODE_SINGLE_RFP 1 #define RF_CORE_FRONT_END_MODE_SINGLE_RFN 2 diff --git a/arch/platform/srf06-cc26xx/platform.c b/arch/platform/srf06-cc26xx/platform.c index bfda15dad..362b9614e 100644 --- a/arch/platform/srf06-cc26xx/platform.c +++ b/arch/platform/srf06-cc26xx/platform.c @@ -128,7 +128,7 @@ set_rf_params(void) NETSTACK_RADIO.set_value(RADIO_PARAM_PAN_ID, IEEE802154_PANID); NETSTACK_RADIO.set_value(RADIO_PARAM_16BIT_ADDR, short_addr); - NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, RF_CORE_CHANNEL); + NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, IEEE802154_DEFAULT_CHANNEL); NETSTACK_RADIO.set_object(RADIO_PARAM_64BIT_ADDR, ext_addr, 8); /* also set the global node id */ diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h index f007eb403..c69ceb209 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h @@ -33,7 +33,7 @@ /*---------------------------------------------------------------------------*/ /* Change to match your configuration */ #define IEEE802154_CONF_PANID 0xABCD -#define RF_CORE_CONF_CHANNEL 25 +#define IEEE802154_CONF_DEFAULT_CHANNEL 25 #define RF_BLE_CONF_ENABLED 1 /*---------------------------------------------------------------------------*/ diff --git a/examples/platform-specific/cc26xx/project-conf.h b/examples/platform-specific/cc26xx/project-conf.h index 8231dd4ea..17bd2ce29 100644 --- a/examples/platform-specific/cc26xx/project-conf.h +++ b/examples/platform-specific/cc26xx/project-conf.h @@ -36,7 +36,7 @@ /*---------------------------------------------------------------------------*/ /* Change to match your configuration */ #define IEEE802154_CONF_PANID 0xABCD -#define RF_CORE_CONF_CHANNEL 25 +#define IEEE802154_CONF_DEFAULT_CHANNEL 25 #define RF_BLE_CONF_ENABLED 1 /*---------------------------------------------------------------------------*/ #endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/cc26xx/very-sleepy-demo/project-conf.h b/examples/platform-specific/cc26xx/very-sleepy-demo/project-conf.h index b60df036d..f22fb2685 100644 --- a/examples/platform-specific/cc26xx/very-sleepy-demo/project-conf.h +++ b/examples/platform-specific/cc26xx/very-sleepy-demo/project-conf.h @@ -33,7 +33,7 @@ /*---------------------------------------------------------------------------*/ /* Change to match your configuration */ #define IEEE802154_CONF_PANID 0xABCD -#define RF_CORE_CONF_CHANNEL 25 +#define IEEE802154_CONF_DEFAULT_CHANNEL 25 /*---------------------------------------------------------------------------*/ /* Enable the ROM bootloader */ From 2359cdb7c04948cda676a37ce660ee6b7aaadc7d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 02:31:28 -0700 Subject: [PATCH 046/129] jn516x: use IEEE802154_DEFAULT_CHANNEL --- arch/platform/jn516x/contiki-conf.h | 8 -------- arch/platform/jn516x/dev/micromac-radio.c | 7 +------ examples/platform-specific/jn516x/rpl/common-conf.h | 2 -- examples/platform-specific/jn516x/tsch/common-conf.h | 2 -- 4 files changed, 1 insertion(+), 18 deletions(-) diff --git a/arch/platform/jn516x/contiki-conf.h b/arch/platform/jn516x/contiki-conf.h index f8dbdc3e5..e4d741400 100644 --- a/arch/platform/jn516x/contiki-conf.h +++ b/arch/platform/jn516x/contiki-conf.h @@ -40,14 +40,6 @@ #include "jn516x-def.h" -#ifdef RF_CHANNEL -#define MICROMAC_CONF_CHANNEL RF_CHANNEL -#endif - -#ifndef MICROMAC_CONF_CHANNEL -#define MICROMAC_CONF_CHANNEL 26 -#endif - /* Configure radio driver */ #ifndef NETSTACK_CONF_RADIO #define NETSTACK_CONF_RADIO micromac_radio_driver diff --git a/arch/platform/jn516x/dev/micromac-radio.c b/arch/platform/jn516x/dev/micromac-radio.c index 3ebc13578..6e2ddb908 100644 --- a/arch/platform/jn516x/dev/micromac-radio.c +++ b/arch/platform/jn516x/dev/micromac-radio.c @@ -100,11 +100,6 @@ #define MIRCOMAC_CONF_BUF_NUM 2 #endif /* MIRCOMAC_CONF_BUF_NUM */ -/* Init radio channel */ -#ifndef MICROMAC_CONF_CHANNEL -#define MICROMAC_CONF_CHANNEL 26 -#endif - /* Default energy level threshold for clear channel detection */ #ifndef MICROMAC_CONF_CCA_THR #define MICROMAC_CONF_CCA_THR 39 /* approximately -85 dBm */ @@ -159,7 +154,7 @@ static uint8_t autoack_enabled = MICROMAC_CONF_AUTOACK; static uint8_t send_on_cca = 0; /* Current radio channel */ -static int current_channel = MICROMAC_CONF_CHANNEL; +static int current_channel = IEEE802154_DEFAULT_CHANNEL; /* Current set point tx power Actual tx power may be different. Use get_txpower() for actual power */ diff --git a/examples/platform-specific/jn516x/rpl/common-conf.h b/examples/platform-specific/jn516x/rpl/common-conf.h index daa66ae29..8ffb3b4f5 100644 --- a/examples/platform-specific/jn516x/rpl/common-conf.h +++ b/examples/platform-specific/jn516x/rpl/common-conf.h @@ -72,8 +72,6 @@ #define IEEE802154_CONF_PANID 0xabcd -#define MICROMAC_CONF_CHANNEL 26 - /* UART Configuration */ #define UART_HW_FLOW_CTRL 0 diff --git a/examples/platform-specific/jn516x/tsch/common-conf.h b/examples/platform-specific/jn516x/tsch/common-conf.h index 39d012d52..5911f34ee 100644 --- a/examples/platform-specific/jn516x/tsch/common-conf.h +++ b/examples/platform-specific/jn516x/tsch/common-conf.h @@ -104,8 +104,6 @@ #if MAC_CONF_WITH_CSMA /* Configure Csma with ACK (default MAC) */ -#define MICROMAC_CONF_CHANNEL 26 - #define MICROMAC_CONF_AUTOACK 1 /* increase internal radio buffering */ From d1288984208bd8a3989ee556e7b95f08157fb345 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 02:33:02 -0700 Subject: [PATCH 047/129] cc2420: use IEEE802154_DEFAULT_CHANNEL --- arch/dev/cc2420/cc2420.c | 2 +- arch/dev/cc2420/cc2420.h | 4 ---- arch/platform/sky/contiki-conf.h | 4 ---- arch/platform/sky/platform.c | 4 ++-- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/arch/dev/cc2420/cc2420.c b/arch/dev/cc2420/cc2420.c index 9310ec9e4..5cfa00e4a 100644 --- a/arch/dev/cc2420/cc2420.c +++ b/arch/dev/cc2420/cc2420.c @@ -641,7 +641,7 @@ cc2420_init(void) init_security(); cc2420_set_pan_addr(0xffff, 0x0000, NULL); - cc2420_set_channel(CC2420_CONF_CHANNEL); + cc2420_set_channel(IEEE802154_DEFAULT_CHANNEL); cc2420_set_cca_threshold(CC2420_CONF_CCA_THRESH); flushrx(); diff --git a/arch/dev/cc2420/cc2420.h b/arch/dev/cc2420/cc2420.h index a030632a6..07b578aa4 100644 --- a/arch/dev/cc2420/cc2420.h +++ b/arch/dev/cc2420/cc2420.h @@ -50,10 +50,6 @@ #define WITH_SEND_CCA 1 -#ifndef CC2420_CONF_CHANNEL -#define CC2420_CONF_CHANNEL 26 -#endif /* CC2420_CONF_CHANNEL */ - #ifndef CC2420_CONF_CCA_THRESH #define CC2420_CONF_CCA_THRESH -45 #endif /* CC2420_CONF_CCA_THRESH */ diff --git a/arch/platform/sky/contiki-conf.h b/arch/platform/sky/contiki-conf.h index 500e00e08..8df4549ef 100644 --- a/arch/platform/sky/contiki-conf.h +++ b/arch/platform/sky/contiki-conf.h @@ -11,10 +11,6 @@ #include "sky-def.h" #include "msp430-def.h" /*---------------------------------------------------------------------------*/ -/* Map RF_CHANNEL to cc2420 default channel */ -#ifdef RF_CHANNEL -#define CC2420_CONF_CHANNEL RF_CHANNEL -#endif /* RF_CHANNEL */ /* Configure radio driver */ #ifndef NETSTACK_CONF_RADIO diff --git a/arch/platform/sky/platform.c b/arch/platform/sky/platform.c index d71471340..bbc273bf0 100644 --- a/arch/platform/sky/platform.c +++ b/arch/platform/sky/platform.c @@ -207,11 +207,11 @@ platform_init_stage_three(void) #if NETSTACK_CONF_WITH_IPV6 LOG_INFO("%s, rf channel %u, CCA threshold %i\n", NETSTACK_MAC.name, - CC2420_CONF_CHANNEL, + IEEE802154_DEFAULT_CHANNEL, CC2420_CONF_CCA_THRESH); #else /* NETSTACK_CONF_WITH_IPV6 */ LOG_INFO("%s, rf channel %u\n", - NETSTACK_MAC.name, CC2420_CONF_CHANNEL); + NETSTACK_MAC.name, IEEE802154_DEFAULT_CHANNEL); #endif /* NETSTACK_CONF_WITH_IPV6 */ #if !NETSTACK_CONF_WITH_IPV6 From d8cdc5f802776917e932291e57de6d57e7cd9ffa Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 02:34:49 -0700 Subject: [PATCH 048/129] Adopt IEEE802154_DEFAULT_CHANNEL in examples that use it --- examples/coap/coap-example-server.c | 4 ++-- examples/coap/plugtest-server.c | 4 ++-- examples/coap/project-conf.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/coap/coap-example-server.c b/examples/coap/coap-example-server.c index 41ea53744..798f7627d 100644 --- a/examples/coap/coap-example-server.c +++ b/examples/coap/coap-example-server.c @@ -107,8 +107,8 @@ PROCESS_THREAD(er_example_server, ev, data) PRINTF("Starting Erbium Example Server\n"); -#ifdef RF_CHANNEL - PRINTF("RF channel: %u\n", RF_CHANNEL); +#ifdef IEEE802154_DEFAULT_CHANNEL + PRINTF("RF channel: %u\n", IEEE802154_DEFAULT_CHANNEL); #endif #ifdef IEEE802154_PANID PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); diff --git a/examples/coap/plugtest-server.c b/examples/coap/plugtest-server.c index 7ca53bc2d..c3b005d1d 100644 --- a/examples/coap/plugtest-server.c +++ b/examples/coap/plugtest-server.c @@ -82,8 +82,8 @@ PROCESS_THREAD(plugtest_server, ev, data) PRINTF("ETSI IoT CoAP Plugtests Server\n"); -#ifdef RF_CHANNEL - PRINTF("RF channel: %u\n", RF_CHANNEL); +#ifdef IEEE802154_DEFAULT_CHANNEL + PRINTF("RF channel: %u\n", IEEE802154_DEFAULT_CHANNEL); #endif #ifdef IEEE802154_PANID PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); diff --git a/examples/coap/project-conf.h b/examples/coap/project-conf.h index 115d6fbb0..e7294b5ec 100644 --- a/examples/coap/project-conf.h +++ b/examples/coap/project-conf.h @@ -40,7 +40,7 @@ #define PROJECT_ERBIUM_CONF_H_ /* Custom channel and PAN ID configuration for your project. */ -/* #define RF_CHANNEL 26 */ +/* #define IEEE802154_CONF_DEFAULT_CHANNEL 26 */ /* #define IEEE802154_CONF_PANID 0xABCD */ /* IP buffer size must match all other hops, in particular the border router. */ From df90e62b883dc61003345d62e5db2df2577be46c Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 02:35:44 -0700 Subject: [PATCH 049/129] Cooja: remove leftover RF_CHANNEL --- arch/platform/cooja/contiki-conf.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/platform/cooja/contiki-conf.h b/arch/platform/cooja/contiki-conf.h index 75a37f866..048497462 100644 --- a/arch/platform/cooja/contiki-conf.h +++ b/arch/platform/cooja/contiki-conf.h @@ -133,7 +133,6 @@ typedef uint64_t rtimer_clock_t; #define CFS_CONF_OFFSET_TYPE long -#define RF_CHANNEL 26 #define NETSTACK_RADIO_MAX_PAYLOAD_LEN 125 #define PLATFORM_CONF_SUPPORTS_STACK_CHECK 0 From 3325c44f4ed6e61df24693595bd8b8e009f44700 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 02:54:16 -0700 Subject: [PATCH 050/129] Main: print out 802.15.4 panid and channel, as well as routing layer configuration --- os/contiki-main.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/os/contiki-main.c b/os/contiki-main.c index 234b759ee..86c50f7ec 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -86,9 +86,15 @@ main(void) platform_init_stage_two(); LOG_INFO("Starting " CONTIKI_VERSION_STRING "\n"); - - LOG_INFO(" Net: %s\n", NETSTACK_NETWORK.name); - LOG_INFO(" MAC: %s\n", NETSTACK_MAC.name); + LOG_INFO("- Routing: %s\n", NETSTACK_ROUTING.name); + LOG_INFO("- Net: %s\n", NETSTACK_NETWORK.name); + LOG_INFO("- MAC: %s\n", NETSTACK_MAC.name); + LOG_INFO("- 802.15.4 PANID: 0x%04x\n", IEEE802154_PANID); +#if MAC_CONF_WITH_CSMA + LOG_INFO("- 802.15.4 Channel: %u\n", IEEE802154_DEFAULT_CHANNEL); +#elif MAC_CONF_WITH_TSCH + LOG_INFO("- 802.15.4 TSCH default hopping sequence length: %u\n", (unsigned)sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)); +#endif netstack_init(); From f933767b4ca29c0c5196d6107b5ca14bc28bb56d Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 02:58:40 -0700 Subject: [PATCH 051/129] Remove now unnecessary pintouts of 802.15.4 panid and channel --- arch/platform/sky/platform.c | 10 +--------- examples/coap/coap-example-server.c | 7 ------- examples/coap/plugtest-server.c | 7 ------- 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/arch/platform/sky/platform.c b/arch/platform/sky/platform.c index bbc273bf0..deaa53b5a 100644 --- a/arch/platform/sky/platform.c +++ b/arch/platform/sky/platform.c @@ -204,15 +204,7 @@ platform_init_stage_three(void) LOG_INFO("Node id: N/A\n"); } -#if NETSTACK_CONF_WITH_IPV6 - LOG_INFO("%s, rf channel %u, CCA threshold %i\n", - NETSTACK_MAC.name, - IEEE802154_DEFAULT_CHANNEL, - CC2420_CONF_CCA_THRESH); -#else /* NETSTACK_CONF_WITH_IPV6 */ - LOG_INFO("%s, rf channel %u\n", - NETSTACK_MAC.name, IEEE802154_DEFAULT_CHANNEL); -#endif /* NETSTACK_CONF_WITH_IPV6 */ + LOG_INFO("CC2420 CCA threshold %i\n", CC2420_CONF_CCA_THRESH); #if !NETSTACK_CONF_WITH_IPV6 uart1_set_input(serial_line_input_byte); diff --git a/examples/coap/coap-example-server.c b/examples/coap/coap-example-server.c index 798f7627d..776ebcd5c 100644 --- a/examples/coap/coap-example-server.c +++ b/examples/coap/coap-example-server.c @@ -107,13 +107,6 @@ PROCESS_THREAD(er_example_server, ev, data) PRINTF("Starting Erbium Example Server\n"); -#ifdef IEEE802154_DEFAULT_CHANNEL - PRINTF("RF channel: %u\n", IEEE802154_DEFAULT_CHANNEL); -#endif -#ifdef IEEE802154_PANID - PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); -#endif - PRINTF("uIP buffer: %u\n", UIP_BUFSIZE); PRINTF("LL header: %u\n", UIP_LLH_LEN); PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); diff --git a/examples/coap/plugtest-server.c b/examples/coap/plugtest-server.c index c3b005d1d..b0d08c023 100644 --- a/examples/coap/plugtest-server.c +++ b/examples/coap/plugtest-server.c @@ -82,13 +82,6 @@ PROCESS_THREAD(plugtest_server, ev, data) PRINTF("ETSI IoT CoAP Plugtests Server\n"); -#ifdef IEEE802154_DEFAULT_CHANNEL - PRINTF("RF channel: %u\n", IEEE802154_DEFAULT_CHANNEL); -#endif -#ifdef IEEE802154_PANID - PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); -#endif - PRINTF("uIP buffer: %u\n", UIP_BUFSIZE); PRINTF("LL header: %u\n", UIP_LLH_LEN); PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); From 87bb684bb44b62c6a0b5faadd817c6ea2785487f Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 02:58:54 -0700 Subject: [PATCH 052/129] Fix rpl-udp-sky.csc --- examples/rpl-udp/rpl-udp-sky.csc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rpl-udp/rpl-udp-sky.csc b/examples/rpl-udp/rpl-udp-sky.csc index 7975acf05..4b9ce6099 100644 --- a/examples/rpl-udp/rpl-udp-sky.csc +++ b/examples/rpl-udp/rpl-udp-sky.csc @@ -24,7 +24,7 @@ sky1 Sky Mote Type #sky1 [CONTIKI_DIR]/examples/rpl-udp/udp-server.c - make clean udp-server.sky TARGET=sky + make udp-server.sky TARGET=sky [CONTIKI_DIR]/examples/rpl-udp/udp-server.sky org.contikios.cooja.interfaces.Position org.contikios.cooja.interfaces.RimeAddress @@ -47,7 +47,7 @@ sky2 Sky Mote Type #sky2 [CONTIKI_DIR]/examples/rpl-udp/udp-client.c - make clean udp-client.sky TARGET=sky + make udp-client.sky TARGET=sky [CONTIKI_DIR]/examples/rpl-udp/udp-client.sky org.contikios.cooja.interfaces.Position org.contikios.cooja.interfaces.RimeAddress From 0750824f19e1a4608c14312f00b59a9018543dc0 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 04:00:55 -0700 Subject: [PATCH 053/129] Fix nullrouting for compilation with nullnet --- os/net/routing/nullrouting/nullrouting.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/os/net/routing/nullrouting/nullrouting.c b/os/net/routing/nullrouting/nullrouting.c index 14c328b0c..a32e0804c 100644 --- a/os/net/routing/nullrouting/nullrouting.c +++ b/os/net/routing/nullrouting/nullrouting.c @@ -106,7 +106,9 @@ local_repair(const char *str) static void ext_header_remove(void) { +#if NETSTACK_CONF_WITH_IPV6 uip_ext_len = 0; +#endif /* NETSTACK_CONF_WITH_IPV6 */ } /*---------------------------------------------------------------------------*/ static int From 5d350182d5d08f1ce52db3c8ba8a8efef7dbc994 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 08:01:19 -0700 Subject: [PATCH 054/129] CoAP example: remove unnecessary commented-out config flags --- examples/coap/project-conf.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/coap/project-conf.h b/examples/coap/project-conf.h index e7294b5ec..ff7549358 100644 --- a/examples/coap/project-conf.h +++ b/examples/coap/project-conf.h @@ -39,10 +39,6 @@ #ifndef PROJECT_ERBIUM_CONF_H_ #define PROJECT_ERBIUM_CONF_H_ -/* Custom channel and PAN ID configuration for your project. */ -/* #define IEEE802154_CONF_DEFAULT_CHANNEL 26 */ -/* #define IEEE802154_CONF_PANID 0xABCD */ - /* IP buffer size must match all other hops, in particular the border router. */ /* #define UIP_CONF_BUFFER_SIZE 256 */ From bacdfcb253afec5ecb5aa3cfcdf98eb5305f5725 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 14:54:07 +0200 Subject: [PATCH 055/129] Doxygen for tsch.h --- os/net/mac/tsch/tsch.h | 52 +++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 5f2289c66..4a153f464 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -180,21 +180,57 @@ PROCESS_NAME(tsch_pending_events_process); /********** Functions *********/ -/* The the TSCH join priority */ +/** + * Set the TSCH join priority (JP) + * + * \param jp the new join priority + */ void tsch_set_join_priority(uint8_t jp); -/* The period at which EBs are sent */ +/** + * Set the period at wich TSCH enhanced beacons (EBs) are sent. The period can + * not be set to exceed TSCH_MAX_EB_PERIOD. Set to 0 to stop sending EBs. + * Actual transmissions are jittered, spaced by a random number within + * [period*0.75, period[ + * + * \param period The period in Clock ticks. + */ void tsch_set_eb_period(uint32_t period); -/* The keep-alive timeout */ +/** + * Set the desynchronization timeout after which a node sends a unicasst + * keep-alive (KA) to its time source. Set to 0 to stop sending KAs. The + * actual timeout is a random number within + * [timeout*0.9, timeout[ + * + * \param timeout The timeout in Clock ticks. + */ void tsch_set_ka_timeout(uint32_t timeout); -/* Set the node as PAN coordinator */ +/** + * Set the node as PAN coordinator + * + * \param enable 1 to be coordinator, 0 to be a node + */ void tsch_set_coordinator(int enable); -/* Set the pan as secured or not */ +/** + * Enable/disable security. If done at the coordinator, the Information + * will be included in EBs, and all nodes will adopt the same security level. + * Enabling requires compilation with LLSEC802154_ENABLED set. + * Note: when LLSEC802154_ENABLED is set, nodes boot with security enabled. + * + * \param enable 1 to enable security, 0 to disable it + */ void tsch_set_pan_secured(int enable); -/* Set TSCH to send a keepalive message after TSCH_KEEPALIVE_TIMEOUT */ +/** + * Schedule a keep-alive transmission within [timeout*0.9, timeout[ + * @see tsch_set_ka_timeout + */ void tsch_schedule_keepalive(void); -/* Set TSCH to send a keepalive message immediately */ +/** + * Schedule a keep-alive immediately + */ void tsch_schedule_keepalive_immediately(void); -/* Leave the TSCH network */ +/** + * Leave the TSCH network we are currently in + */ void tsch_disassociate(void); #endif /* __TSCH_H__ */ From 533351f4dd8adf21437947cac245d45d9fbb86aa Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 14:54:16 +0200 Subject: [PATCH 056/129] Doxygen for tsch-types.h --- os/net/mac/tsch/tsch-types.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/os/net/mac/tsch/tsch-types.h b/os/net/mac/tsch/tsch-types.h index 6bc8895a2..6eb0f19a9 100644 --- a/os/net/mac/tsch/tsch-types.h +++ b/os/net/mac/tsch/tsch-types.h @@ -53,10 +53,10 @@ /********** Data types **********/ -/* 802.15.4e link types. - * LINK_TYPE_ADVERTISING_ONLY is an extra one: for EB-only links. */ +/** \brief 802.15.4e link types. LINK_TYPE_ADVERTISING_ONLY is an extra one: for EB-only links. */ enum link_type { LINK_TYPE_NORMAL, LINK_TYPE_ADVERTISING, LINK_TYPE_ADVERTISING_ONLY }; +/** \brief An IEEE 802.15.4-2015 TSCH link (also called cell or slot) */ struct tsch_link { /* Links are stored as a list: "next" must be the first field */ struct tsch_link *next; @@ -83,7 +83,7 @@ struct tsch_link { void *data; }; -/* 802.15.4e slotframe (contains links) */ +/** \brief 802.15.4e slotframe (contains links) */ struct tsch_slotframe { /* Slotframes are stored as a list: "next" must be the first field */ struct tsch_slotframe *next; @@ -96,7 +96,7 @@ struct tsch_slotframe { LIST_STRUCT(links_list); }; -/* TSCH packet information */ +/** \brief TSCH packet information */ struct tsch_packet { struct queuebuf *qb; /* pointer to the queuebuf to be sent */ mac_callback_t sent; /* callback for this packet */ @@ -108,7 +108,7 @@ struct tsch_packet { uint8_t tsch_sync_ie_offset; /* Offset within the frame used for quick update of EB ASN and join priority */ }; -/* TSCH neighbor information */ +/** \brief TSCH neighbor information */ struct tsch_neighbor { /* Neighbors are stored as a list: "next" must be the first field */ struct tsch_neighbor *next; @@ -127,7 +127,7 @@ struct tsch_neighbor { struct ringbufindex tx_ringbuf; }; -/* TSCH timeslot timing elements. Used to index timeslot timing +/** \brief TSCH timeslot timing elements. Used to index timeslot timing * of different units, such as rtimer tick or micro-second */ enum tsch_timeslot_timing_elements { tsch_ts_cca_offset, @@ -145,7 +145,7 @@ enum tsch_timeslot_timing_elements { tsch_ts_elements_count, /* Not a timing element */ }; -/* Stores data about an incoming packet */ +/** \brief Stores data about an incoming packet */ struct input_packet { uint8_t payload[TSCH_PACKET_MAX_LEN]; /* Packet payload */ struct tsch_asn_t rx_asn; /* ASN when the packet was received */ From a48bf54668f80249762f7af912e631adb906eb94 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 7 Apr 2018 14:54:26 +0200 Subject: [PATCH 057/129] Doxygen for tsch-slot-operation.h --- os/net/mac/tsch/tsch-slot-operation.h | 40 ++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/os/net/mac/tsch/tsch-slot-operation.h b/os/net/mac/tsch/tsch-slot-operation.h index 1702ce199..63a9fbb51 100644 --- a/os/net/mac/tsch/tsch-slot-operation.h +++ b/os/net/mac/tsch/tsch-slot-operation.h @@ -58,19 +58,45 @@ extern clock_time_t last_sync_time; /********** Functions *********/ -/* Returns a 802.15.4 channel from an ASN and channel offset */ +/** + * Returns a 802.15.4 channel from an ASN and channel offset. Basically adds + * The offset to the ASN and performs a hopping sequence lookup. + * + * \param asn A given ASN + * \param channel_offset A given channel offset + * \return The resulting channel + */ uint8_t tsch_calculate_channel(struct tsch_asn_t *asn, uint8_t channel_offset); -/* Is TSCH locked? */ +/** + * Checks if the TSCH lock is set. Accesses to global structures outside of + * interrupts must be done through the lock, unless the sturcutre has + * atomic read/write + * + * \return 1 if the lock is taken, 0 otherwise + */ int tsch_is_locked(void); -/* Lock TSCH (no link operation) */ +/** + * Takes the TSCH lock. When the lock is taken, slot operation will be skipped + * until release. + * + * \return 1 if the lock was successfully taken, 0 otherwise + */ int tsch_get_lock(void); -/* Release TSCH lock */ +/** + * Releases the TSCH lock. + */ void tsch_release_lock(void); -/* Set global time before starting slot operation, - * with a rtimer time and an ASN */ +/** + * Set global time before starting slot operation, with a rtimer time and an ASN + * + * \param next_slot_start the time to the start of the next slot, in rtimer ticks + * \param next_slot_asn the ASN of the next slot + */ void tsch_slot_operation_sync(rtimer_clock_t next_slot_start, struct tsch_asn_t *next_slot_asn); -/* Start actual slot operation */ +/** + * Start actual slot operation + */ void tsch_slot_operation_start(void); #endif /* __TSCH_SLOT_OPERATION_H__ */ From 8be446d0ea9bc57ac9753fd423c64b2b61f88de1 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 14 Apr 2018 12:09:16 -0700 Subject: [PATCH 058/129] Doxygen for tsch-schedule.h --- os/net/mac/tsch/tsch-schedule.h | 105 +++++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 16 deletions(-) diff --git a/os/net/mac/tsch/tsch-schedule.h b/os/net/mac/tsch/tsch-schedule.h index 2a2cf5e25..9a9a7330f 100644 --- a/os/net/mac/tsch/tsch-schedule.h +++ b/os/net/mac/tsch/tsch-schedule.h @@ -45,42 +45,115 @@ /********** Functions *********/ -/* Module initialization, call only once at startup. Returns 1 is success, 0 if failure. */ +/** + * \brief Module initialization, call only once at init + * \return 1 if success, 0 if failure + */ int tsch_schedule_init(void); -/* Create a 6TiSCH minimal schedule */ +/** + * \brief Create a 6tisch minimal schedule with length TSCH_SCHEDULE_DEFAULT_LENGTH + */ void tsch_schedule_create_minimal(void); -/* Prints out the current schedule (all slotframes and links) */ +/** + * \brief Prints out the current schedule (all slotframes and links) + */ void tsch_schedule_print(void); -/* Adds and returns a slotframe (NULL if failure) */ + +/** + * \brief Creates and adds a new slotframe + * \param handle the slotframe handle + * \param size the slotframe size + * \return the new slotframe, NULL if failure + */ struct tsch_slotframe *tsch_schedule_add_slotframe(uint16_t handle, uint16_t size); -/* Looks for a slotframe from a handle */ + +/** + * \brief Looks up a slotframe by handle + * \param handle the slotframe handle + * \return the slotframe with required handle, if any. NULL otherwise. + */ struct tsch_slotframe *tsch_schedule_get_slotframe_by_handle(uint16_t handle); -/* Removes a slotframe Return 1 if success, 0 if failure */ + +/** + * \brief Removes a slotframe + * \param slotframe The slotframe to be removed + * \return 1 if success, 0 if failure + */ int tsch_schedule_remove_slotframe(struct tsch_slotframe *slotframe); -/* Removes all slotframes, resulting in an empty schedule */ + +/** + * \brief Removes all slotframes, resulting in an empty schedule + * \return 1 if success, 0 if failure + */ int tsch_schedule_remove_all_slotframes(void); -/* Returns next slotframe */ -struct tsch_slotframe *tsch_schedule_slotframes_next(struct tsch_slotframe *sf); -/* Adds a link to a slotframe, return a pointer to it (NULL if failure) */ +/** + * \brief Adds a link to a slotframe + * \param slotframe The slotframe that will contain the new link + * \param link_options The link options, as a bitfield (LINK_OPTION_* flags) + * \param link_type The link type (advertising, normal) + * \param address The link address of the intended destination. Use &tsch_broadcast_address for a slot towards any neighbor + * \param timeslot The link timeslot within the slotframe + * \param channel_offset The link channel offset + * \return A pointer to the new link, NULL if failure + */ struct tsch_link *tsch_schedule_add_link(struct tsch_slotframe *slotframe, uint8_t link_options, enum link_type link_type, const linkaddr_t *address, uint16_t timeslot, uint16_t channel_offset); -/* Looks for a link from a handle */ +/** +* \brief Looks for a link from a handle +* \param handle The target handle +* \return The link with required handle, if any. Otherwise, NULL +*/ struct tsch_link *tsch_schedule_get_link_by_handle(uint16_t handle); -/* Looks within a slotframe for a link with a given timeslot */ + +/** + * \brief Looks within a slotframe for a link with a given timeslot + * \param slotframe The desired slotframe + * \param timeslot The desired timeslot + * \return The link if found, NULL otherwise + */ struct tsch_link *tsch_schedule_get_link_by_timeslot(struct tsch_slotframe *slotframe, uint16_t timeslot); -/* Removes a link. Return 1 if success, 0 if failure */ + +/** + * \brief Removes a link + * \param slotframe The slotframe the link belongs to + * \param l The link to be removed + * \return 1 if success, 0 if failure + */ int tsch_schedule_remove_link(struct tsch_slotframe *slotframe, struct tsch_link *l); -/* Removes a link from slotframe and timeslot. Return a 1 if success, 0 if failure */ + +/** + * \brief Removes a link from a slotframe and timeslot + * \param slotframe The slotframe where to look for the link + * \param timeslot The timeslot where to look for the link within the target slotframe + * \return 1 if success, 0 if failure + */ int tsch_schedule_remove_link_by_timeslot(struct tsch_slotframe *slotframe, uint16_t timeslot); -/* Returns the next active link after a given ASN, and a backup link (for the same ASN, with Rx flag) */ + +/** + * \brief Returns the next active link after a given ASN, and a backup link (for the same ASN, with Rx flag) + * \param asn The base ASN, from which we look for the next active link + * \param time_offset A pointer to uint16_t where to store the time offset between base ASN and link found + * \param backup_link A pointer where to write the address of a backup link, to be executed should the original be no longer active at wakeup + * \return The next active link if any, NULL otherwise + */ struct tsch_link * tsch_schedule_get_next_active_link(struct tsch_asn_t *asn, uint16_t *time_offset, struct tsch_link **backup_link); -/* Access to slotframe list */ + +/** + * \brief Access the first item in the list of slotframes + * \return The first slotframe in the schedule if any, NULL otherwise + */ struct tsch_slotframe *tsch_schedule_slotframe_head(void); + +/** + * \brief Access the next item in the list of slotframes + * \param sf The current slotframe (item in the list) + * \return The next slotframe if any, NULL otherwise + */ struct tsch_slotframe *tsch_schedule_slotframe_next(struct tsch_slotframe *sf); #endif /* __TSCH_SCHEDULE_H__ */ From 68ec94e0fb2af8e5cc54c7d7b5241b4b938e1634 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 14 Apr 2018 12:10:25 -0700 Subject: [PATCH 059/129] Doxygen for tsch-asn.h --- os/net/mac/tsch/tsch-asn.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/os/net/mac/tsch/tsch-asn.h b/os/net/mac/tsch/tsch-asn.h index 9895cdcf4..d58e7b27e 100644 --- a/os/net/mac/tsch/tsch-asn.h +++ b/os/net/mac/tsch/tsch-asn.h @@ -48,13 +48,13 @@ /************ Types ***********/ -/* The ASN is an absolute slot number over 5 bytes. */ +/** \brief The ASN is an absolute slot number over 5 bytes. */ struct tsch_asn_t { uint32_t ls4b; /* least significant 4 bytes */ uint8_t ms1b; /* most significant 1 byte */ }; -/* For quick modulo operation on ASN */ +/** \brief For quick modulo operation on ASN */ struct tsch_asn_divisor_t { uint16_t val; /* Divisor value */ uint16_t asn_ms1b_remainder; /* Remainder of the operation 0x100000000 / val */ @@ -62,37 +62,37 @@ struct tsch_asn_divisor_t { /************ Macros **********/ -/* Initialize ASN */ +/** \brief Initialize ASN */ #define TSCH_ASN_INIT(asn, ms1b_, ls4b_) do { \ (asn).ms1b = (ms1b_); \ (asn).ls4b = (ls4b_); \ } while(0); -/* Increment an ASN by inc (32 bits) */ +/** \brief Increment an ASN by inc (32 bits) */ #define TSCH_ASN_INC(asn, inc) do { \ uint32_t new_ls4b = (asn).ls4b + (inc); \ if(new_ls4b < (asn).ls4b) { (asn).ms1b++; } \ (asn).ls4b = new_ls4b; \ } while(0); -/* Decrement an ASN by inc (32 bits) */ +/** \brief Decrement an ASN by inc (32 bits) */ #define TSCH_ASN_DEC(asn, dec) do { \ uint32_t new_ls4b = (asn).ls4b - (dec); \ if(new_ls4b > (asn).ls4b) { (asn).ms1b--; } \ (asn).ls4b = new_ls4b; \ } while(0); -/* Returns the 32-bit diff between asn1 and asn2 */ +/** \brief Returns the 32-bit diff between asn1 and asn2 */ #define TSCH_ASN_DIFF(asn1, asn2) \ ((asn1).ls4b - (asn2).ls4b) -/* Initialize a struct asn_divisor_t */ +/** \brief Initialize a struct asn_divisor_t */ #define TSCH_ASN_DIVISOR_INIT(div, val_) do { \ (div).val = (val_); \ (div).asn_ms1b_remainder = ((0xffffffff % (val_)) + 1) % (val_); \ } while(0); -/* Returns the result (16 bits) of a modulo operation on ASN, +/** \brief Returns the result (16 bits) of a modulo operation on ASN, * with divisor being a struct asn_divisor_t */ #define TSCH_ASN_MOD(asn, div) \ ((uint16_t)((asn).ls4b % (div).val) \ From eb814872672350e1305988b2e02d07705da73703 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 14 Apr 2018 12:15:55 -0700 Subject: [PATCH 060/129] Doxygen for tsch-rpl.h --- os/net/mac/tsch/tsch-rpl.h | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/os/net/mac/tsch/tsch-rpl.h b/os/net/mac/tsch/tsch-rpl.h index 64e31166c..0c71b0076 100644 --- a/os/net/mac/tsch/tsch-rpl.h +++ b/os/net/mac/tsch/tsch-rpl.h @@ -47,20 +47,35 @@ /********** Functions *********/ -/* Keep-alives packet sent callback. - * To use, set #define TSCH_CALLBACK_KA_SENT tsch_rpl_callback_ka_sent */ +/** +* \brief Report statiscs from KA packet sent in RPL. +* To use, set TSCH_CALLBACK_KA_SENT to tsch_rpl_callback_ka_sent +* \param status The packet sent status +* \param transmissions The total number of transmissions +*/ void tsch_rpl_callback_ka_sent(int status, int transmissions); -/* To use, set #define TSCH_CALLBACK_JOINING_NETWORK tsch_rpl_callback_joining_network */ +/** + * \brief Let RPL know that TSCH joined a new network. + * To use, set TSCH_CALLBACK_JOINING_NETWORK to tsch_rpl_callback_joining_network + */ void tsch_rpl_callback_joining_network(void); -/* Upon leaving a TSCH network, perform a local repair - * (cleanup neighbor state, reset Trickle timer etc) - * To use, set #define TSCH_CALLBACK_LEAVING_NETWORK tsch_rpl_callback_leaving_network */ +/** + * \brief Let RPL know that TSCH joined a new network. Triggers a local repair. + * To use, set TSCH_CALLBACK_LEAVING_NETWORK to tsch_rpl_callback_leaving_network + */ void tsch_rpl_callback_leaving_network(void); -/* Set TSCH EB period based on current RPL DIO period. - * To use, set #define RPL_CALLBACK_NEW_DIO_INTERVAL tsch_rpl_callback_new_dio_interval */ +/** + * \brief Set TSCH EB period based on current RPL DIO period. + * To use, set RPL_CALLBACK_NEW_DIO_INTERVAL to tsch_rpl_callback_new_dio_interval + * \param dio_interval The new DIO interval in clock ticks + */ void tsch_rpl_callback_new_dio_interval(clock_time_t dio_interval); -/* Set TSCH time source based on current RPL preferred parent. - * To use, set #define RPL_CALLBACK_PARENT_SWITCH tsch_rpl_callback_parent_switch */ +/** + * \brief Set TSCH time source based on current RPL preferred parent. + * To use, set RPL_CALLBACK_PARENT_SWITCH to tsch_rpl_callback_parent_switch + * \param old The old RPL parent + * \param new The new RPL parent + */ void tsch_rpl_callback_parent_switch(rpl_parent_t *old, rpl_parent_t *new); #endif /* __TSCH_RPL_H__ */ From 5734b32a6f75f021ff96ae9a896add5367fbf611 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 14 Apr 2018 12:18:14 -0700 Subject: [PATCH 061/129] Doxygen for tsch-log.h --- os/net/mac/tsch/tsch-log.h | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/os/net/mac/tsch/tsch-log.h b/os/net/mac/tsch/tsch-log.h index 198304b43..a16747cc0 100644 --- a/os/net/mac/tsch/tsch-log.h +++ b/os/net/mac/tsch/tsch-log.h @@ -70,7 +70,7 @@ /************ Types ***********/ -/* Structure for a log. Union of different types of logs */ +/** \brief Structure for a log. Union of different types of logs */ struct tsch_log_t { enum { tsch_log_tx, tsch_log_rx, @@ -107,21 +107,31 @@ struct tsch_log_t { /********** Functions *********/ -/* Prepare addition of a new log. - * Returns pointer to log structure if success, NULL otherwise */ +/** + * \brief Prepare addition of a new log. + * \return A pointer to log structure if success, NULL otherwise + */ struct tsch_log_t *tsch_log_prepare_add(void); -/* Actually add the previously prepared log */ +/** + * \brief Actually add the previously prepared log + */ void tsch_log_commit(void); -/* Initialize log module */ +/** + * \brief Initialize log module + */ void tsch_log_init(void); -/* Process pending log messages */ +/** + * \brief Process pending log messages + */ void tsch_log_process_pending(void); -/* Stop logging module */ +/** + * \brief Stop logging module + */ void tsch_log_stop(void); /************ Macros **********/ -/* Use this macro to add a log to the queue (will be printed out +/** \brief Use this macro to add a log to the queue (will be printed out * later, after leaving interrupt context) */ #define TSCH_LOG_ADD(log_type, init_code) do { \ struct tsch_log_t *log = tsch_log_prepare_add(); \ From 3728350ad4a91d248766540c92d98b415a757e5a Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 14 Apr 2018 12:25:04 -0700 Subject: [PATCH 062/129] Doxygen for tsch-adaptive-sync.h --- os/net/mac/tsch/tsch-adaptive-timesync.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/os/net/mac/tsch/tsch-adaptive-timesync.h b/os/net/mac/tsch/tsch-adaptive-timesync.h index be61b9514..574add542 100644 --- a/os/net/mac/tsch/tsch-adaptive-timesync.h +++ b/os/net/mac/tsch/tsch-adaptive-timesync.h @@ -44,15 +44,30 @@ /***** External Variables *****/ -/* The neighbor last used as our time source */ +/** \brief The neighbor last used as our time source */ extern struct tsch_neighbor *last_timesource_neighbor; /********** Functions *********/ +/** + * \brief Updates timesync information for a given neighbor + * \param n The neighbor + * \param time_delta_asn ASN time delta since last synchronization, i.e. number of slots elapsed + * \param drift_correction The measured drift in ticks since last synchronization + */ void tsch_timesync_update(struct tsch_neighbor *n, uint16_t time_delta_asn, int32_t drift_correction); +/** + * \brief Computes time compensation for a given point in the future + * \param delta_ticks The number of ticks in the future we want to calculate compensation for + * \return The time compensation + */ int32_t tsch_timesync_adaptive_compensate(rtimer_clock_t delta_ticks); +/** + * \brief Gives the estimated clock drift w.r.t. the time source in PPM (parts per million) + * \return The time drift in PPM + */ long int tsch_adaptive_timesync_get_drift_ppm(void); #endif /* __TSCH_ADAPTIVE_TIMESYNC_H__ */ From 0f41b9d1a6bde678bd716fed37300ff475817573 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 17 Apr 2018 12:36:43 -0700 Subject: [PATCH 063/129] tsch_packet_update_eb: fix return value to indicate failures --- os/net/mac/tsch/tsch-packet.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/os/net/mac/tsch/tsch-packet.c b/os/net/mac/tsch/tsch-packet.c index e0e253a3f..64f03b588 100644 --- a/os/net/mac/tsch/tsch-packet.c +++ b/os/net/mac/tsch/tsch-packet.c @@ -390,8 +390,7 @@ tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset) struct ieee802154_ies ies; ies.ie_asn = tsch_current_asn; ies.ie_join_priority = tsch_join_priority; - frame80215e_create_ie_tsch_synchronization(buf+tsch_sync_ie_offset, buf_size-tsch_sync_ie_offset, &ies); - return 1; + return frame80215e_create_ie_tsch_synchronization(buf+tsch_sync_ie_offset, buf_size-tsch_sync_ie_offset, &ies) != -1; } /*---------------------------------------------------------------------------*/ /* Parse a IEEE 802.15.4e TSCH Enhanced Beacon (EB) */ From 6dc34c128fd0f45685a64030ccdb5a7c4fc07455 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 17 Apr 2018 12:36:59 -0700 Subject: [PATCH 064/129] Doxygen for tsch-packet.h --- os/net/mac/tsch/tsch-packet.h | 48 +++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/os/net/mac/tsch/tsch-packet.h b/os/net/mac/tsch/tsch-packet.h index 4dfbcbe72..1706ad97d 100644 --- a/os/net/mac/tsch/tsch-packet.h +++ b/os/net/mac/tsch/tsch-packet.h @@ -46,18 +46,56 @@ /********** Functions *********/ -/* Construct enhanced ACK packet and return ACK length */ +/** + * \brief Construct Enhanced ACK packet + * \param buf The buffer where to build the EACK + * \param buf_size The buffer size + * \param dest_addr The link-layer address of the neighbor we are ACKing + * \param seqno The sequence number we are ACKing + * \param drift The time offset in usec measured at Rx of the packer we are ACKing + * \param nack Value of the NACK bit + * \return The length of the packet that was created. -1 if failure. + */ int tsch_packet_create_eack(uint8_t *buf, uint16_t buf_size, const linkaddr_t *dest_addr, uint8_t seqno, int16_t drift, int nack); -/* Parse enhanced ACK packet, extract drift and nack */ +/** + * \brief Parse enhanced ACK packet + * \param buf The buffer where to parse the EACK from + * \param buf_size The buffer size + * \param seqno The sequence number we are expecting + * \param frame The frame structure where to store parsed fields + * \param ies The IE structure where to store parsed IEs + * \param hdr_len A pointer where to store the length of the parsed header + * \return 1 if the EACK is correct and acknowledges the specified frame, 0 otherwise + */ int tsch_packet_parse_eack(const uint8_t *buf, int buf_size, uint8_t seqno, frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len); -/* Create an EB packet */ +/** + * \brief Create an EB packet directly in packetbuf + * \param hdr_len A pointer where to store the length of the created header + * \param tsch_sync_ie_ptr A pointer where to store the address of the TSCH synchronization IE + * \return The total length of the EB + */ int tsch_packet_create_eb(uint8_t *hdr_len, uint8_t *tsch_sync_ie_ptr); -/* Update ASN in EB packet */ +/** + * \brief Update ASN in EB packet + * \param buf The buffer that contains the EB + * \param buf_size The buffer size + * \param tsch_sync_ie_offset The offset of the TSCH synchronization IE, in which the ASN is to be written + * \return 1 if success, 0 otherwise + */ int tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset); -/* Parse EB and extract ASN and join priority */ +/** + * \brief Parse EB + * \param buf The buffer where to parse the EB from + * \param buf_size The buffer sizecting + * \param frame The frame structure where to store parsed fields + * \param ies The IE structure where to store parsed IEs + * \param hdrlen A pointer where to store the length of the parsed header + * \param frame_without_mic When set, the security MIC will not be parsed + * \return The length of the parsed EB + */ int tsch_packet_parse_eb(const uint8_t *buf, int buf_size, frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdrlen, int frame_without_mic); From 10ada6084927b460654c209917e0c9e4a70b7c06 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 17 Apr 2018 12:58:43 -0700 Subject: [PATCH 065/129] Doxygen for tsch-queue.h --- os/net/mac/tsch/tsch-queue.h | 124 ++++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 23 deletions(-) diff --git a/os/net/mac/tsch/tsch-queue.h b/os/net/mac/tsch/tsch-queue.h index 8c7dceb37..fcf460c97 100644 --- a/os/net/mac/tsch/tsch-queue.h +++ b/os/net/mac/tsch/tsch-queue.h @@ -53,50 +53,128 @@ extern struct tsch_neighbor *n_eb; /********** Functions *********/ -/* Add a TSCH neighbor */ +/** + * \brief Add a TSCH neighbor queue + * \param addr The link-layer address of the neighbor to be added + */ struct tsch_neighbor *tsch_queue_add_nbr(const linkaddr_t *addr); -/* Get a TSCH neighbor */ +/** + * \brief Get a TSCH neighbor + * \param addr The link-layer address of the neighbor we are looking for + * \return A pointer to the neighbor queue, NULL if not found + */ struct tsch_neighbor *tsch_queue_get_nbr(const linkaddr_t *addr); -/* Get a TSCH time source (we currently assume there is only one) */ +/** + * \brief Get the TSCH time source (we currently assume there is only one) + * \return The neighbor queue associated to the time source + */ struct tsch_neighbor *tsch_queue_get_time_source(void); -/* Update TSCH time source */ +/** + * \brief Update TSCH time source + * \param new_addr The address of the new TSCH time source + */ int tsch_queue_update_time_source(const linkaddr_t *new_addr); -/* Add packet to neighbor queue. Use same lockfree implementation as ringbuf.c (put is atomic) */ +/** + * \brief Add packet to neighbor queue. Use same lockfree implementation as ringbuf.c (put is atomic) + * \param addr The address of the targetted neighbor, &tsch_broadcast_address for broadcast + * \param max_transmissions The number of MAC retries + * \param sent The MAC packet sent callback + * \param ptr The MAC packet send callback parameter + * \return The newly created packet if any, NULL otherwise + */ struct tsch_packet *tsch_queue_add_packet(const linkaddr_t *addr, uint8_t max_transmissions, mac_callback_t sent, void *ptr); -/* Returns the number of packets currently in any TSCH queue */ +/** + * \brief Returns the number of packets currently in all TSCH queues + * \return The number of packets currently in all TSCH queues + */ int tsch_queue_global_packet_count(void); -/* Returns the number of packets currently a given neighbor queue */ +/** + * \brief Returns the number of packets currently a given neighbor queue + * \param addr The link-layer address of the neighbor we are interested in + * \return The number of packets in the neighbor's queue + */ int tsch_queue_packet_count(const linkaddr_t *addr); -/* Remove first packet from a neighbor queue. The packet is stored in a separate - * dequeued packet list, for later processing. Return the packet. */ +/** + * \brief Remove first packet from a neighbor queue. The packet is stored in a separate + * dequeued packet list, for later processing. + * \param n The neighbor queue + * \return The packet that was removed if any, NULL otherwise + */ struct tsch_packet *tsch_queue_remove_packet_from_queue(struct tsch_neighbor *n); -/* Free a packet */ +/** + * \brief Free a packet + * \param p The packet to be freed + */ void tsch_queue_free_packet(struct tsch_packet *p); -/* Updates neighbor queue state after a transmission */ +/** + * \brief Updates neighbor queue state after a transmission + * \param n The neighbor queue we just sent from + * \param p The packet that was just sent + * \param link The TSCH link used for Tx + * \param mac_tx_status The MAC status (see mac.h) + * \return 1 if the packet remains in queue after the call, 0 if it was removed + */ int tsch_queue_packet_sent(struct tsch_neighbor *n, struct tsch_packet *p, struct tsch_link *link, uint8_t mac_tx_status); -/* Reset neighbor queues */ +/** + * \brief Reset neighbor queues module + */ void tsch_queue_reset(void); -/* Deallocate neighbors with empty queue */ +/** + * \brief Deallocate all neighbors with empty queue + */ void tsch_queue_free_unused_neighbors(void); -/* Is the neighbor queue empty? */ +/** + * \brief Is the neighbor queue empty? + * \param n The neighbor queue + * \return 1 if empty, 0 otherwise + */ int tsch_queue_is_empty(const struct tsch_neighbor *n); -/* Returns the first packet from a neighbor queue */ +/** + * \brief Returns the first packet that can be sent from a queue on a given link + * \param n The neighbor queue + * \param link The link + * \return The next packet to be sent for the neighbor on the given link, if any, else NULL + */ struct tsch_packet *tsch_queue_get_packet_for_nbr(const struct tsch_neighbor *n, struct tsch_link *link); -/* Returns the head packet from a neighbor queue (from neighbor address) */ +/** + * \brief Returns the first packet that can be sent to a given address on a given link + * \param addr The target link-layer address + * \param link The link + * \return The next packet to be sent for to the given address on the given link, if any, else NULL + */ struct tsch_packet *tsch_queue_get_packet_for_dest_addr(const linkaddr_t *addr, struct tsch_link *link); -/* Returns the head packet of any neighbor queue with zero backoff counter. - * Writes pointer to the neighbor in *n */ +/** + * \brief Gets the head packet of any neighbor queue with zero backoff counter. + * \param n A pointer where to store the neighbor queue to be used for Tx + * \param link The link to be used for Tx + * \return The packet if any, else NULL + */ struct tsch_packet *tsch_queue_get_unicast_packet_for_any(struct tsch_neighbor **n, struct tsch_link *link); -/* May the neighbor transmit over a share link? */ +/** + * \brief Is the neighbor backoff timer expired? + * \param n The neighbor queue + * \return 1 if the backoff has expired (neighbor ready to transmit on a shared link), 0 otherwise + */ int tsch_queue_backoff_expired(const struct tsch_neighbor *n); -/* Reset neighbor backoff */ +/** + * \brief Reset neighbor backoff + * \param n The neighbor queue + */ void tsch_queue_backoff_reset(struct tsch_neighbor *n); -/* Increment backoff exponent, pick a new window */ +/** + * \brief Increment backoff exponent of a given neighbor queue, pick a new window + * \param n The neighbor queue + */ void tsch_queue_backoff_inc(struct tsch_neighbor *n); -/* Decrement backoff window for all queues directed at dest_addr */ +/** + * \brief Decrement backoff window for the queue(s) able to Tx to a given address + * \param dest_addr The target address, &tsch_broadcast_address for broadcast + */ void tsch_queue_update_all_backoff_windows(const linkaddr_t *dest_addr); -/* Initialize TSCH queue module */ +/** + * \brief Initialize TSCH queue module + */ void tsch_queue_init(void); #endif /* __TSCH_QUEUE_H__ */ From 32d4a7271632bab00f1f82f02a67e2e31848d8fa Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 18 Apr 2018 12:02:00 -0700 Subject: [PATCH 066/129] cc26xx 6lbr client example: use only whith RPL Classic --- examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile | 7 ++++++- .../cc26xx/cc26xx-web-demo/cetic-6lbr-client.c | 7 ++++--- .../cc26xx/cc26xx-web-demo/project-conf.h | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile b/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile index 3ddf9671b..05dbface1 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/Makefile @@ -5,9 +5,14 @@ PLATFORMS_ONLY = srf06-cc26xx MODULES_REL += ./resources -PROJECT_SOURCEFILES += cetic-6lbr-client.c coap-server.c net-uart.c mqtt-client.c +PROJECT_SOURCEFILES += coap-server.c net-uart.c mqtt-client.c PROJECT_SOURCEFILES += httpd-simple.c +ifeq ($(MAKE_ROUTING),MAKE_ROUTING_RPL_CLASSIC) +# 6lbr only supports RPL Classic +PROJECT_SOURCEFILES += cetic-6lbr-client.c +endif + # REST Engine shall use Erbium CoAP implementation MODULES += os/net/app-layer/mqtt MODULES += os/net/app-layer/coap diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c index d3042bf81..dbdc0d3a0 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c @@ -37,10 +37,11 @@ #include "contiki-net.h" #include "net/routing/routing.h" #include "net/ipv6/uip.h" -#if ROUTING_CONF_RPL_LITE -#include "net/routing/rpl-lite/rpl.h" -#elif ROUTING_CONF_RPL_CLASSIC +#if ROUTING_CONF_RPL_CLASSIC #include "net/routing/rpl-classic/rpl.h" +#include "net/routing/rpl-classic/rpl-private.h" +#else +#error The 6LBR client is only meant for RPL Classic. Set MAKE_ROUTING accordingly. #endif #include diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h index f007eb403..c5078bf38 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h @@ -42,7 +42,7 @@ /* Enable/Disable Components of this Demo */ #define CC26XX_WEB_DEMO_CONF_MQTT_CLIENT 1 -#define CC26XX_WEB_DEMO_CONF_6LBR_CLIENT 1 +#define CC26XX_WEB_DEMO_CONF_6LBR_CLIENT ROUTING_CONF_RPL_CLASSIC #define CC26XX_WEB_DEMO_CONF_COAP_SERVER 1 #define CC26XX_WEB_DEMO_CONF_NET_UART 1 From dcb248500f35fcfc3ec7f08cd1ea064759de2ab8 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 18 Apr 2018 12:03:09 -0700 Subject: [PATCH 067/129] cc26xx 6lbr client example: fix compilation with RPL Classic --- .../cc26xx/cc26xx-web-demo/cetic-6lbr-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c b/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c index dbdc0d3a0..569a36a89 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/cetic-6lbr-client.c @@ -161,8 +161,8 @@ timeout_handler(void) PRINT6ADDR(&client_conn->ripaddr); i = sprintf(buf, "%d | ", ++seq_id); instance = rpl_get_default_instance(); - if(instance && instance->dag.preferred_parent) { - add_ipaddr(buf + i, rpl_parent_get_ipaddr(instance->dag.preferred_parent)); + if(instance && instance->current_dag->preferred_parent) { + add_ipaddr(buf + i, rpl_parent_get_ipaddr(instance->current_dag->preferred_parent)); } else { sprintf(buf + i, "(null)"); } From 95e02300f33749fcd21c6a9564616928b772ddec Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 18 Apr 2018 12:03:50 -0700 Subject: [PATCH 068/129] cc26xx web demo example: add compile test with RPL Classic, in order to build 6lbr client --- tests/02-compile-arm-ports-01/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index 1ecf59fe4..77cce805b 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -3,6 +3,7 @@ TOOLSDIR=../../tools EXAMPLES = \ platform-specific/cc26xx/cc26xx-web-demo/srf06-cc26xx \ +platform-specific/cc26xx/cc26xx-web-demo/srf06-cc26xx:MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC \ platform-specific/cc26xx/very-sleepy-demo/srf06-cc26xx:BOARD=sensortag/cc2650 \ platform-specific/cc26xx/cc26xx-web-demo/srf06-cc26xx:BOARD=sensortag/cc2650 \ platform-specific/cc26xx/cc26xx-web-demo/srf06-cc26xx:BOARD=sensortag/cc1350 \ From ff7c3ee0429fea758a9bde8ce86ea5b19f0512ad Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 20 Apr 2018 02:44:58 -0700 Subject: [PATCH 069/129] Make rtimer 32-bit by default --- arch/cpu/arm/arm-def.h | 2 -- arch/cpu/msp430/msp430-def.h | 50 ++++++++++++++------------ arch/cpu/msp430/rtimer-arch.h | 4 --- arch/platform/jn516x/dev/rtimer-arch.h | 14 +++----- arch/platform/jn516x/jn516x-def.h | 4 --- os/sys/rtimer.h | 5 +-- 6 files changed, 35 insertions(+), 44 deletions(-) diff --git a/arch/cpu/arm/arm-def.h b/arch/cpu/arm/arm-def.h index 92b19048d..c83cfd3fc 100644 --- a/arch/cpu/arm/arm-def.h +++ b/arch/cpu/arm/arm-def.h @@ -57,8 +57,6 @@ typedef uint32_t clock_time_t; typedef uint32_t uip_stats_t; -typedef uint32_t rtimer_clock_t; -#define RTIMER_CLOCK_DIFF(a, b) ((int32_t)((a) - (b))) /** @} */ /* diff --git a/arch/cpu/msp430/msp430-def.h b/arch/cpu/msp430/msp430-def.h index 93e575702..2801ec8c3 100644 --- a/arch/cpu/msp430/msp430-def.h +++ b/arch/cpu/msp430/msp430-def.h @@ -1,30 +1,30 @@ /* * Copyright (c) 2007, Swedish Institute of Computer Science - * All rights reserved. + * All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ #ifndef MSP430_DEF_H_ @@ -79,6 +79,10 @@ typedef long off_t; /* Our clock resolution, this is the same as Unix HZ. */ #define CLOCK_CONF_SECOND 128UL +/* Use 16-bit rtimer (default in Contiki-NG is 32) */ +typedef unsigned short rtimer_clock_t; +#define RTIMER_CLOCK_DIFF(a,b) ((signed short)((a)-(b))) + typedef int spl_t; spl_t splhigh_(void); diff --git a/arch/cpu/msp430/rtimer-arch.h b/arch/cpu/msp430/rtimer-arch.h index 6063292b1..9fd5b46ba 100644 --- a/arch/cpu/msp430/rtimer-arch.h +++ b/arch/cpu/msp430/rtimer-arch.h @@ -42,11 +42,7 @@ #include "sys/rtimer.h" -#ifdef RTIMER_CONF_SECOND -#define RTIMER_ARCH_SECOND RTIMER_CONF_SECOND -#else #define RTIMER_ARCH_SECOND (4096U*8) -#endif /* Do the math in 32bits to save precision. * Round to nearest integer rather than truncate. */ diff --git a/arch/platform/jn516x/dev/rtimer-arch.h b/arch/platform/jn516x/dev/rtimer-arch.h index 3ffafeeac..63212566b 100644 --- a/arch/platform/jn516x/dev/rtimer-arch.h +++ b/arch/platform/jn516x/dev/rtimer-arch.h @@ -43,19 +43,15 @@ #include "sys/rtimer.h" -#ifdef RTIMER_CONF_SECOND -# define RTIMER_ARCH_SECOND RTIMER_CONF_SECOND -#else #if RTIMER_USE_32KHZ -# if JN516X_EXTERNAL_CRYSTAL_OSCILLATOR -# define RTIMER_ARCH_SECOND 32768 -# else -# define RTIMER_ARCH_SECOND 32000 +#if JN516X_EXTERNAL_CRYSTAL_OSCILLATOR +#define RTIMER_ARCH_SECOND 32768 +#else +#define RTIMER_ARCH_SECOND 32000 #endif #else /* 32MHz CPU clock => 16MHz timer */ -# define RTIMER_ARCH_SECOND (F_CPU / 2) -#endif +#define RTIMER_ARCH_SECOND (F_CPU / 2) #endif #if RTIMER_USE_32KHZ diff --git a/arch/platform/jn516x/jn516x-def.h b/arch/platform/jn516x/jn516x-def.h index 0c76a4332..a4ee45c75 100644 --- a/arch/platform/jn516x/jn516x-def.h +++ b/arch/platform/jn516x/jn516x-def.h @@ -79,10 +79,6 @@ #define JN516X_EXTERNAL_CRYSTAL_OSCILLATOR (RTIMER_USE_32KHZ || JN516X_SLEEP_ENABLED) #endif /* JN516X_EXTERNAL_CRYSTAL_OSCILLATOR */ -/* Core rtimer.h defaults to 16 bit timer unless RTIMER_CLOCK_DIFF is defined */ -typedef uint32_t rtimer_clock_t; -#define RTIMER_CLOCK_DIFF(a, b) ((int32_t)((a) - (b))) - /* 8ms timer tick */ #define CLOCK_CONF_SECOND 125 diff --git a/os/sys/rtimer.h b/os/sys/rtimer.h index 95d11c33d..6cccaab49 100644 --- a/os/sys/rtimer.h +++ b/os/sys/rtimer.h @@ -56,8 +56,9 @@ #include "contiki.h" #ifndef RTIMER_CLOCK_DIFF -typedef unsigned short rtimer_clock_t; -#define RTIMER_CLOCK_DIFF(a,b) ((signed short)((a)-(b))) +/* By default: 32-bit rtimer. Set RTIMER_CLOCK_DIFF for custom rtimer width */ +typedef uint32_t rtimer_clock_t; +#define RTIMER_CLOCK_DIFF(a, b) ((int32_t)((a) - (b))) #endif /* RTIMER_CLOCK_DIFF */ #define RTIMER_CLOCK_LT(a, b) (RTIMER_CLOCK_DIFF((a),(b)) < 0) From f339747218f47315eec76f6d698ada87e8fe4c06 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 20 Apr 2018 05:06:40 -0700 Subject: [PATCH 070/129] rtimer: homogenize clock size configuration --- arch/cpu/msp430/msp430-def.h | 3 +-- arch/platform/cooja/contiki-conf.h | 5 +++-- os/sys/rtimer.h | 32 +++++++++++++++++++++++++----- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/arch/cpu/msp430/msp430-def.h b/arch/cpu/msp430/msp430-def.h index 2801ec8c3..28b482e9a 100644 --- a/arch/cpu/msp430/msp430-def.h +++ b/arch/cpu/msp430/msp430-def.h @@ -80,8 +80,7 @@ typedef long off_t; #define CLOCK_CONF_SECOND 128UL /* Use 16-bit rtimer (default in Contiki-NG is 32) */ -typedef unsigned short rtimer_clock_t; -#define RTIMER_CLOCK_DIFF(a,b) ((signed short)((a)-(b))) +#define RTIMER_CONF_CLOCK_SIZE 2 typedef int spl_t; spl_t splhigh_(void); diff --git a/arch/platform/cooja/contiki-conf.h b/arch/platform/cooja/contiki-conf.h index 048497462..9fb0a990a 100644 --- a/arch/platform/cooja/contiki-conf.h +++ b/arch/platform/cooja/contiki-conf.h @@ -113,8 +113,9 @@ typedef unsigned short uip_stats_t; #define CLOCK_CONF_SECOND 1000L typedef unsigned long clock_time_t; -typedef uint64_t rtimer_clock_t; -#define RTIMER_CLOCK_DIFF(a,b) ((int64_t)((a)-(b))) + +/* Use 64-bit rtimer (default in Contiki-NG is 32) */ +#define RTIMER_CONF_CLOCK_SIZE 8 #define RADIO_DELAY_BEFORE_TX 0 #define RADIO_DELAY_BEFORE_RX 0 diff --git a/os/sys/rtimer.h b/os/sys/rtimer.h index 6cccaab49..44ad92a2f 100644 --- a/os/sys/rtimer.h +++ b/os/sys/rtimer.h @@ -55,12 +55,34 @@ #include "contiki.h" -#ifndef RTIMER_CLOCK_DIFF -/* By default: 32-bit rtimer. Set RTIMER_CLOCK_DIFF for custom rtimer width */ -typedef uint32_t rtimer_clock_t; -#define RTIMER_CLOCK_DIFF(a, b) ((int32_t)((a) - (b))) -#endif /* RTIMER_CLOCK_DIFF */ +/** \brief The rtimer size (in bytes) */ +#ifdef RTIMER_CONF_CLOCK_SIZE +#define RTIMER_CLOCK_SIZE RTIMER_CONF_CLOCK_SIZE +#else /* RTIMER_CONF_CLOCK_SIZE */ +/* Default: 32bit rtimer*/ +#define RTIMER_CLOCK_SIZE 4 +#endif /* RTIMER_CONF_CLOCK_SIZE */ +#if RTIMER_CLOCK_SIZE == 2 +/* 16-bit rtimer */ +typedef uint16_t rtimer_clock_t; +#define RTIMER_CLOCK_DIFF(a,b) ((int16_t)((a)-(b))) + +#elif RTIMER_CLOCK_SIZE == 4 +/* 32-bit rtimer */ +typedef uint32_t rtimer_clock_t; +#define RTIMER_CLOCK_DIFF(a, b) ((int32_t)((a) - (b))) + +#elif RTIMER_CLOCK_SIZE == 8 +/* 64-bit rtimer */ +typedef uint64_t rtimer_clock_t; +#define RTIMER_CLOCK_DIFF(a,b) ((int64_t)((a)-(b))) + +#else +#error Unsupported rtimer size (check RTIMER_CLOCK_SIZE) +#endif + +#define RTIMER_CLOCK_MAX ((rtimer_clock_t)-1) #define RTIMER_CLOCK_LT(a, b) (RTIMER_CLOCK_DIFF((a),(b)) < 0) #include "rtimer-arch.h" From c5e8c2097f2494cf37767d4beabae34e935658d4 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 20 Apr 2018 05:24:07 -0700 Subject: [PATCH 071/129] Remove leftover COOJA_IP64 flags --- os/net/mac/csma/csma-output.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/os/net/mac/csma/csma-output.c b/os/net/mac/csma/csma-output.c index 59949c040..9c88d569d 100644 --- a/os/net/mac/csma/csma-output.c +++ b/os/net/mac/csma/csma-output.c @@ -50,10 +50,10 @@ #include "lib/list.h" #include "lib/memb.h" -#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 +#if CONTIKI_TARGET_COOJA #include "lib/simEnvChange.h" #include "sys/cooja_mt.h" -#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */ +#endif /* CONTIKI_TARGET_COOJA */ /* Log configuration */ #include "sys/log.h" @@ -207,10 +207,10 @@ send_one_packet(void *ptr) wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + CSMA_ACK_WAIT_TIME)) { -#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 +#if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); -#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */ +#endif /* CONTIKI_TARGET_COOJA */ } ret = MAC_TX_NOACK; @@ -225,10 +225,10 @@ send_one_packet(void *ptr) watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + CSMA_AFTER_ACK_DETECTED_WAIT_TIME)) { -#if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 +#if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); -#endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */ +#endif /* CONTIKI_TARGET_COOJA */ } } From 0d07edf700ea597640915472c0bf59fbadb811f8 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 08:24:59 -0700 Subject: [PATCH 072/129] CoAP example: tidy up makefile --- examples/coap/Makefile | 33 ++++++---------------- examples/coap/sky/module-macros.h | 47 ------------------------------- 2 files changed, 8 insertions(+), 72 deletions(-) delete mode 100644 examples/coap/sky/module-macros.h diff --git a/examples/coap/Makefile b/examples/coap/Makefile index 1195a37a3..1b7d2db28 100644 --- a/examples/coap/Makefile +++ b/examples/coap/Makefile @@ -1,5 +1,4 @@ CONTIKI_PROJECT = coap-example-server coap-example-client -# use target "plugtest-server" explicitly when required all: $(CONTIKI_PROJECT) @@ -8,31 +7,15 @@ CONTIKI=../.. # Do not try to build on Sky because of code size limitation PLATFORMS_EXCLUDE = sky -# build RESTful resources -include $(CONTIKI)/Makefile.identify-target -ifeq ($(TARGET),native) - MODULES_REL += ./resources-plugtest -endif -MODULES_REL += ./resources -MODULES_REL += $(TARGET) - # Include the CoAP implementation MODULES += os/net/app-layer/coap +include $(CONTIKI)/Makefile.identify-target +ifeq ($(TARGET),native) +# Include Plugtest resources only for target native, where code size is unconstrained + MODULES_REL += ./resources-plugtest +endif +# Include CoAP resources +MODULES_REL += ./resources + include $(CONTIKI)/Makefile.include - -# border router rules -$(CONTIKI)/tools/tunslip6: $(CONTIKI)/tools/tunslip6.c - (cd $(CONTIKI)/tools && $(MAKE) tunslip6) - -connect-router: $(CONTIKI)/tools/tunslip6 - sudo $(CONTIKI)/tools/tunslip6 fd00::1/64 - -connect-router-cooja: $(CONTIKI)/tools/tunslip6 - sudo $(CONTIKI)/tools/tunslip6 -a 127.0.0.1 -p 60001 fd00::1/64 - -connect-router-native: $(CONTIKI)/examples/rpl-border-router/border-router.native - sudo $(CONTIKI)/examples/rpl-border-router/border-router.native -a 127.0.0.1 -p 60001 fd00::1/64 - -connect-native: - sudo ip address add fdfd::1/64 dev tun0 diff --git a/examples/coap/sky/module-macros.h b/examples/coap/sky/module-macros.h deleted file mode 100644 index 3fcb04015..000000000 --- a/examples/coap/sky/module-macros.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018, RISE SICS AB. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#error The CoAP example no longer fits the limited ROM in the Tmote Sky. \ - Please select another platform with more ROM to compile the CoAP example. - -/*---------------------------------------------------------------------------*/ -#define COAP_OBSERVE_CLIENT 0 - -#define COAP_MAX_CHUNK_SIZE 48 - -/* Turn off DAO-ACK and probing to make code smaller */ -#define RPL_CONF_WITH_DAO_ACK 0 - -#define LOG_CONF_LEVEL_MAIN 0 - -#define DCOSYNCH_CONF_ENABLED 0 - -#define PROCESS_CONF_NUMEVENTS 8 -/*---------------------------------------------------------------------------*/ From 22da4903457814ed0e3f26b847894e76e58acf36 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 08:29:15 -0700 Subject: [PATCH 073/129] Code style --- examples/coap/resources/res-hello.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/coap/resources/res-hello.c b/examples/coap/resources/res-hello.c index 46b0139ef..914bc28d6 100644 --- a/examples/coap/resources/res-hello.c +++ b/examples/coap/resources/res-hello.c @@ -75,7 +75,9 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff memcpy(buffer, message, length); } else { memcpy(buffer, message, length); - } coap_set_header_content_format(response, TEXT_PLAIN); /* text/plain is the default, hence this option could be omitted. */ + } + + coap_set_header_content_format(response, TEXT_PLAIN); /* text/plain is the default, hence this option could be omitted. */ coap_set_header_etag(response, (uint8_t *)&length, 1); coap_set_payload(response, buffer, length); } From 4f4db3d252c9413bbbeeb2522069f43e2a7a2a27 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 09:12:49 -0700 Subject: [PATCH 074/129] CoAP examples: split in example-server, example-client and plugtest-server --- examples/coap/Makefile | 21 --- examples/coap/README.md | 88 +-------- examples/coap/coap-example-client/Makefile | 12 ++ .../coap-example-client.c | 4 +- .../coap-example-observe-client.c | 14 +- .../{ => coap-example-client}/project-conf.h | 33 +--- examples/coap/coap-example-server/Makefile | 14 ++ .../coap-example-server.c | 62 ++----- .../coap/coap-example-server/project-conf.h | 44 +++++ .../resources/res-b1-sep-b2.c | 0 .../resources/res-battery.c | 0 .../resources/res-chunks.c | 0 .../resources/res-event.c | 17 +- .../resources/res-hello.c | 0 .../resources/res-leds.c | 19 +- .../resources/res-light.c | 0 .../resources/res-mirror.c | 17 +- .../resources/res-push.c | 0 .../resources/res-radio.c | 0 .../resources/res-separate.c | 0 .../resources/res-sht11.c | 0 .../resources/res-sub.c | 0 .../resources/res-temperature.c | 0 .../resources/res-toggle.c | 0 examples/coap/coap-plugtest-server/Makefile | 14 ++ .../coap-plugtest-server.c} | 20 +- .../project-conf.h} | 18 +- .../resources/res-mirror.c | 171 ++++++++++++++++++ .../resources}/res-plugtest-create1.c | 10 +- .../resources}/res-plugtest-create2.c | 8 +- .../resources}/res-plugtest-create3.c | 10 +- .../resources}/res-plugtest-large-create.c | 6 +- .../resources}/res-plugtest-large-update.c | 6 +- .../resources}/res-plugtest-large.c | 6 +- .../resources}/res-plugtest-links.c | 6 +- .../resources}/res-plugtest-locquery.c | 10 +- .../resources}/res-plugtest-longpath.c | 10 +- .../resources}/res-plugtest-multi.c | 14 +- .../resources}/res-plugtest-obs.c | 18 +- .../resources}/res-plugtest-path.c | 6 +- .../resources}/res-plugtest-query.c | 10 +- .../resources}/res-plugtest-separate.c | 20 +- .../resources}/res-plugtest-test.c | 40 ++-- .../resources}/res-plugtest-validate.c | 32 ++-- 44 files changed, 444 insertions(+), 336 deletions(-) delete mode 100644 examples/coap/Makefile create mode 100644 examples/coap/coap-example-client/Makefile rename examples/coap/{ => coap-example-client}/coap-example-client.c (98%) rename examples/coap/{ => coap-example-client}/coap-example-observe-client.c (95%) rename examples/coap/{ => coap-example-client}/project-conf.h (62%) create mode 100644 examples/coap/coap-example-server/Makefile rename examples/coap/{ => coap-example-server}/coap-example-server.c (76%) create mode 100644 examples/coap/coap-example-server/project-conf.h rename examples/coap/{ => coap-example-server}/resources/res-b1-sep-b2.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-battery.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-chunks.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-event.c (80%) rename examples/coap/{ => coap-example-server}/resources/res-hello.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-leds.c (78%) rename examples/coap/{ => coap-example-server}/resources/res-light.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-mirror.c (91%) rename examples/coap/{ => coap-example-server}/resources/res-push.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-radio.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-separate.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-sht11.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-sub.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-temperature.c (100%) rename examples/coap/{ => coap-example-server}/resources/res-toggle.c (100%) create mode 100644 examples/coap/coap-plugtest-server/Makefile rename examples/coap/{plugtest-server.c => coap-plugtest-server/coap-plugtest-server.c} (91%) rename examples/coap/{plugtest.h => coap-plugtest-server/project-conf.h} (88%) create mode 100644 examples/coap/coap-plugtest-server/resources/res-mirror.c rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-create1.c (94%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-create2.c (94%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-create3.c (94%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-large-create.c (96%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-large-update.c (97%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-large.c (96%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-links.c (95%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-locquery.c (95%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-longpath.c (91%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-multi.c (91%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-obs.c (94%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-path.c (96%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-query.c (94%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-separate.c (93%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-test.c (81%) rename examples/coap/{resources-plugtest => coap-plugtest-server/resources}/res-plugtest-validate.c (87%) diff --git a/examples/coap/Makefile b/examples/coap/Makefile deleted file mode 100644 index 1b7d2db28..000000000 --- a/examples/coap/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -CONTIKI_PROJECT = coap-example-server coap-example-client - -all: $(CONTIKI_PROJECT) - -CONTIKI=../.. - -# Do not try to build on Sky because of code size limitation -PLATFORMS_EXCLUDE = sky - -# Include the CoAP implementation -MODULES += os/net/app-layer/coap - -include $(CONTIKI)/Makefile.identify-target -ifeq ($(TARGET),native) -# Include Plugtest resources only for target native, where code size is unconstrained - MODULES_REL += ./resources-plugtest -endif -# Include CoAP resources -MODULES_REL += ./resources - -include $(CONTIKI)/Makefile.include diff --git a/examples/coap/README.md b/examples/coap/README.md index 67ba38f26..36ec0b022 100644 --- a/examples/coap/README.md +++ b/examples/coap/README.md @@ -1,83 +1,9 @@ -A Quick Introduction to the Erbium (Er) CoAP Engine -=================================================== +# CoAP examples: client, server, and plugtest serverA Quick Introduction to the Erbium (Er) CoAP Engine -EXAMPLE FILES -------------- +* coap-example-server: A CoAP server example showing how to use the CoAP layer to develop server-side applications. +* coap-example-client: A CoAP client that polls the /actuators/toggle resource every 10 seconds and cycles through 4 resources on button press (target address is hard-coded). +* coap-plugtest-server: The server used for draft compliance testing at ETSI IoT CoAP Plugtests. Erbium (Er) participated in Paris, France, March 2012 and Sophia-Antipolis, France, November 2012 (configured for native). -- coap-example-server.c: A CoAP server example showing how to use the CoAP - layer to develop server-side applications. -- coap-example-client.c: A CoAP client that polls the /actuators/toggle resource - every 10 seconds and cycles through 4 resources on button press (target - address is hard-coded). -- plugtest-server.c: The server used for draft compliance testing at ETSI - IoT CoAP Plugtests. Erbium (Er) participated in Paris, France, March 2012 and - Sophia-Antipolis, France, November 2012 (configured for native). - -PRELIMINARIES -------------- - -- Get the Copper (Cu) CoAP user-agent from - [https://addons.mozilla.org/en-US/firefox/addon/copper-270430](https://addons.mozilla.org/en-US/firefox/addon/copper-270430) - -TMOTE SKY HOWTO ---------------- - -The CoAP example no longer fits in the limited ROM of the Tmote Sky. -Please use a platform with larger ROM instead. - -NATIVE HOWTO ------------- - -With the target native you can test your CoAP applications without -constraints, i.e., with large buffers, debug output, memory protection, etc. -The plugtest-server is thought for the native platform, as it requires -an 1280-byte IP buffer and 1024-byte blocks. - - make TARGET=native plugtest-server - sudo ./plugtest-server.native - -Open new terminal - - make connect-native - -- Start Copper and discover resources at coap://[fdfd::ff:fe00:10]:5683/ -- You can enable the ETSI Plugtest menu in Copper's preferences - -Under Windows/Cygwin, WPCAP might need a patch in -\usr\include\w32api\in6addr.h: - - 21,23c21 - < #ifdef __INSIDE_CYGWIN__ - < uint32_t __s6_addr32[4]; - < #endif - --- - > u_int __s6_addr32[4]; - 36d33 - < #ifdef __INSIDE_CYGWIN__ - 39d35 - < #endif - -DETAILS -------- - -Erbium implements the Proposed Standard of CoAP. Central features are commented -in coap-example-server.c. In general, coap supports: - -- All draft-18 header options -- CON Retransmissions (note COAP_MAX_OPEN_TRANSACTIONS) -- Blockwise Transfers (note COAP_MAX_CHUNK_SIZE, see plugtest-server.c for - Block1 uploads) -- Separate Responses (no rest_set_pre_handler() required anymore, note - coap_separate_accept(), _reject(), and _resume()) -- Resource Discovery -- Observing Resources (see EVENT_ and PERIODIC_RESOURCE, note - COAP_MAX_OBSERVERS) - -TODOs ------ - -- Dedicated Observe buffers -- Optimize message struct variable access (directly access struct without copying) -- Observe client -- Multiple If-Match ETags -- (Message deduplication) +The examples can run either on a real device or as native. +In the latter case, just start the executable with enough permissions (e.g. sudo), and you will then be able to reach the node via tun. +A tutorial for setting up the CoAP server example and querying it is provided on the wiki. diff --git a/examples/coap/coap-example-client/Makefile b/examples/coap/coap-example-client/Makefile new file mode 100644 index 000000000..1d3440990 --- /dev/null +++ b/examples/coap/coap-example-client/Makefile @@ -0,0 +1,12 @@ +CONTIKI_PROJECT = coap-example-client +# coap-example-observe-client is outdated but will be ported at a later point +all: $(CONTIKI_PROJECT) + +# Do not try to build on Sky because of code size limitation +PLATFORMS_EXCLUDE = sky + +# Include the CoAP implementation +MODULES += os/net/app-layer/coap + +CONTIKI=../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/coap/coap-example-client.c b/examples/coap/coap-example-client/coap-example-client.c similarity index 98% rename from examples/coap/coap-example-client.c rename to examples/coap/coap-example-client/coap-example-client.c index 27efbbf6e..1606d884a 100644 --- a/examples/coap/coap-example-client.c +++ b/examples/coap/coap-example-client/coap-example-client.c @@ -51,8 +51,8 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "client" -#define LOG_LEVEL LOG_LEVEL_COAP +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_APP /* FIXME: This server address is hard-coded for Cooja and link-local for unconnected border router. */ #define SERVER_EP "coap://[fe80::212:7402:0002:0202]" diff --git a/examples/coap/coap-example-observe-client.c b/examples/coap/coap-example-client/coap-example-observe-client.c similarity index 95% rename from examples/coap/coap-example-observe-client.c rename to examples/coap/coap-example-client/coap-example-observe-client.c index 1dbed0bd4..914a21bdd 100644 --- a/examples/coap/coap-example-observe-client.c +++ b/examples/coap/coap-example-client/coap-example-observe-client.c @@ -47,15 +47,11 @@ #else #include "dev/button-sensor.h" #endif -/*----------------------------------------------------------------------------*/ -#define DEBUG 0 -#if DEBUG -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINTFLN(format, ...) printf(format "\n", ##__VA_ARGS__) -#else -#define PRINTF(...) -#define PRINTFLN(...) -#endif + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_APP /*----------------------------------------------------------------------------*/ /* FIXME: This server address is hard-coded for Cooja */ diff --git a/examples/coap/project-conf.h b/examples/coap/coap-example-client/project-conf.h similarity index 62% rename from examples/coap/project-conf.h rename to examples/coap/coap-example-client/project-conf.h index 115d6fbb0..783e3e84b 100644 --- a/examples/coap/project-conf.h +++ b/examples/coap/coap-example-client/project-conf.h @@ -36,37 +36,12 @@ * Matthias Kovatsch */ -#ifndef PROJECT_ERBIUM_CONF_H_ -#define PROJECT_ERBIUM_CONF_H_ +#ifndef __PROJECT_CONF_H__ +#define __PROJECT_CONF_H__ -/* Custom channel and PAN ID configuration for your project. */ -/* #define RF_CHANNEL 26 */ -/* #define IEEE802154_CONF_PANID 0xABCD */ - -/* IP buffer size must match all other hops, in particular the border router. */ -/* #define UIP_CONF_BUFFER_SIZE 256 */ - -/* Increase rpl-border-router IP-buffer when using more than 64. */ -#define COAP_MAX_CHUNK_SIZE 48 - -/* Estimate your header size, especially when using Proxy-Uri. */ -/* #define COAP_MAX_HEADER_SIZE 70 */ - -/* Multiplies with chunk size, be aware of memory constraints. */ -#ifndef COAP_MAX_OPEN_TRANSACTIONS -#define COAP_MAX_OPEN_TRANSACTIONS 4 -#endif /* COAP_MAX_OPEN_TRANSACTIONS */ - -/* Must be <= open transactions, default is COAP_MAX_OPEN_TRANSACTIONS-1. */ -/* #define COAP_MAX_OBSERVERS 2 */ - -/* Filtering .well-known/core per query can be disabled to save space. */ -#define COAP_LINK_FORMAT_FILTERING 0 -#define COAP_PROXY_OPTION_PROCESSING 0 +#define LOG_LEVEL_APP LOG_LEVEL_DBG /* Enable client-side support for COAP observe */ -#ifndef COAP_OBSERVE_CLIENT #define COAP_OBSERVE_CLIENT 1 -#endif /* COAP_OBSERVE_CLIENT */ -#endif /* PROJECT_ERBIUM_CONF_H_ */ +#endif /* __PROJECT_CONF_H__ */ diff --git a/examples/coap/coap-example-server/Makefile b/examples/coap/coap-example-server/Makefile new file mode 100644 index 000000000..6d9e2db85 --- /dev/null +++ b/examples/coap/coap-example-server/Makefile @@ -0,0 +1,14 @@ +CONTIKI_PROJECT = coap-example-server +all: $(CONTIKI_PROJECT) + +# Do not try to build on Sky because of code size limitation +PLATFORMS_EXCLUDE = sky + +# Include the CoAP implementation +MODULES += os/net/app-layer/coap + +# Include CoAP resources +MODULES_REL += ./resources + +CONTIKI=../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/coap/coap-example-server.c b/examples/coap/coap-example-server/coap-example-server.c similarity index 76% rename from examples/coap/coap-example-server.c rename to examples/coap/coap-example-server/coap-example-server.c index 41ea53744..375fc4bd9 100644 --- a/examples/coap/coap-example-server.c +++ b/examples/coap/coap-example-server/coap-example-server.c @@ -48,14 +48,10 @@ #include "dev/button-sensor.h" #endif -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif - +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_APP /* * Resources to be activated need to be imported through the extern keyword. * The build system automatically compiles the resources in the corresponding sub-directory. @@ -84,17 +80,6 @@ extern coap_resource_t res_battery; #include "dev/temperature-sensor.h" extern coap_resource_t res_temperature; #endif -/* -extern coap_resource_t res_battery; -#endif -#if PLATFORM_HAS_RADIO -extern coap_resource_t res_radio; -#endif -#if PLATFORM_HAS_SHT11 -#include "dev/sht11/sht11-sensor.h" -extern coap_resource_t res_sht11; -#endif -*/ PROCESS(er_example_server, "Erbium Example Server"); AUTOSTART_PROCESSES(&er_example_server); @@ -105,19 +90,7 @@ PROCESS_THREAD(er_example_server, ev, data) PROCESS_PAUSE(); - PRINTF("Starting Erbium Example Server\n"); - -#ifdef RF_CHANNEL - PRINTF("RF channel: %u\n", RF_CHANNEL); -#endif -#ifdef IEEE802154_PANID - PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); -#endif - - PRINTF("uIP buffer: %u\n", UIP_BUFSIZE); - PRINTF("LL header: %u\n", UIP_LLH_LEN); - PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); - PRINTF("CoAP max chunk: %u\n", COAP_MAX_CHUNK_SIZE); + LOG_INFO("Starting Erbium Example Server\n"); /* Initialize the REST engine. */ coap_engine_init(); @@ -128,15 +101,15 @@ PROCESS_THREAD(er_example_server, ev, data) * All static variables are the same for each URI path. */ coap_activate_resource(&res_hello, "test/hello"); - coap_activate_resource(&res_mirror, "debug/mirror"); - coap_activate_resource(&res_chunks, "test/chunks"); - coap_activate_resource(&res_separate, "test/separate"); - coap_activate_resource(&res_push, "test/push"); + coap_activate_resource(&res_mirror, "debug/mirror"); + coap_activate_resource(&res_chunks, "test/chunks"); + coap_activate_resource(&res_separate, "test/separate"); + coap_activate_resource(&res_push, "test/push"); #if PLATFORM_HAS_BUTTON - coap_activate_resource(&res_event, "sensors/button"); + coap_activate_resource(&res_event, "sensors/button"); #endif /* PLATFORM_HAS_BUTTON */ - coap_activate_resource(&res_sub, "test/sub"); - coap_activate_resource(&res_b1_sep_b2, "test/b1sepb2"); + coap_activate_resource(&res_sub, "test/sub"); + coap_activate_resource(&res_b1_sep_b2, "test/b1sepb2"); #if PLATFORM_HAS_LEDS /* coap_activate_resource(&res_leds, "actuators/leds"); */ coap_activate_resource(&res_toggle, "actuators/toggle"); @@ -153,15 +126,6 @@ PROCESS_THREAD(er_example_server, ev, data) coap_activate_resource(&res_temperature, "sensors/temperature"); SENSORS_ACTIVATE(temperature_sensor); #endif -/* -#if PLATFORM_HAS_RADIO - coap_activate_resource(&res_radio, "sensors/radio"); -#endif -#if PLATFORM_HAS_SHT11 - coap_activate_resource(&res_sht11, "sensors/sht11"); - SENSORS_ACTIVATE(sht11_sensor); -#endif -*/ /* Define application-specific events here. */ while(1) { @@ -172,7 +136,7 @@ PROCESS_THREAD(er_example_server, ev, data) #else if(ev == sensors_event && data == &button_sensor) { #endif - PRINTF("*******BUTTON*******\n"); + LOG_DBG("*******BUTTON*******\n"); /* Call the event_handler for this application-specific event. */ res_event.trigger(); diff --git a/examples/coap/coap-example-server/project-conf.h b/examples/coap/coap-example-server/project-conf.h new file mode 100644 index 000000000..436da55a5 --- /dev/null +++ b/examples/coap/coap-example-server/project-conf.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Erbium (Er) example project configuration. + * \author + * Matthias Kovatsch + */ + +#ifndef __PROJECT_CONF_H__ +#define __PROJECT_CONF_H__ + +#define LOG_LEVEL_APP LOG_LEVEL_DBG + +#endif /* __PROJECT_CONF_H__ */ diff --git a/examples/coap/resources/res-b1-sep-b2.c b/examples/coap/coap-example-server/resources/res-b1-sep-b2.c similarity index 100% rename from examples/coap/resources/res-b1-sep-b2.c rename to examples/coap/coap-example-server/resources/res-b1-sep-b2.c diff --git a/examples/coap/resources/res-battery.c b/examples/coap/coap-example-server/resources/res-battery.c similarity index 100% rename from examples/coap/resources/res-battery.c rename to examples/coap/coap-example-server/resources/res-battery.c diff --git a/examples/coap/resources/res-chunks.c b/examples/coap/coap-example-server/resources/res-chunks.c similarity index 100% rename from examples/coap/resources/res-chunks.c rename to examples/coap/coap-example-server/resources/res-chunks.c diff --git a/examples/coap/resources/res-event.c b/examples/coap/coap-example-server/resources/res-event.c similarity index 80% rename from examples/coap/resources/res-event.c rename to examples/coap/coap-example-server/resources/res-event.c index 5640353b3..f8f754afa 100644 --- a/examples/coap/resources/res-event.c +++ b/examples/coap/coap-example-server/resources/res-event.c @@ -41,17 +41,10 @@ #include "coap-engine.h" #include "coap.h" -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) -#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) -#else -#define PRINTF(...) -#define PRINT6ADDR(addr) -#define PRINTLLADDR(addr) -#endif +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_APP static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_event_handler(void); @@ -94,7 +87,7 @@ res_event_handler(void) /* Usually a condition is defined under with subscribers are notified, e.g., event was above a threshold. */ if(1) { - PRINTF("TICK %u for /%s\n", event_counter, res_event.url); + LOG_DBG("TICK %u for /%s\n", (unsigned)event_counter, res_event.url); /* Notify the registered observers which will trigger the res_get_handler to create the response. */ coap_notify_observers(&res_event); diff --git a/examples/coap/resources/res-hello.c b/examples/coap/coap-example-server/resources/res-hello.c similarity index 100% rename from examples/coap/resources/res-hello.c rename to examples/coap/coap-example-server/resources/res-hello.c diff --git a/examples/coap/resources/res-leds.c b/examples/coap/coap-example-server/resources/res-leds.c similarity index 78% rename from examples/coap/resources/res-leds.c rename to examples/coap/coap-example-server/resources/res-leds.c index d601e49f5..72dbc8b41 100644 --- a/examples/coap/resources/res-leds.c +++ b/examples/coap/coap-example-server/resources/res-leds.c @@ -44,17 +44,10 @@ #if PLATFORM_HAS_LEDS || LEDS_COUNT -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) -#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) -#else -#define PRINTF(...) -#define PRINT6ADDR(addr) -#define PRINTLLADDR(addr) -#endif +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_APP static void res_post_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -76,7 +69,7 @@ res_post_put_handler(coap_message_t *request, coap_message_t *response, uint8_t int success = 1; if((len = coap_get_query_variable(request, "color", &color))) { - PRINTF("color %.*s\n", len, color); + LOG_DBG("color %.*s\n", (int)len, color); if(strncmp(color, "r", len) == 0) { led = LEDS_RED; @@ -90,7 +83,7 @@ res_post_put_handler(coap_message_t *request, coap_message_t *response, uint8_t } else { success = 0; } if(success && (len = coap_get_post_variable(request, "mode", &mode))) { - PRINTF("mode %s\n", mode); + LOG_DBG("mode %s\n", mode); if(strncmp(mode, "on", len) == 0) { leds_on(led); diff --git a/examples/coap/resources/res-light.c b/examples/coap/coap-example-server/resources/res-light.c similarity index 100% rename from examples/coap/resources/res-light.c rename to examples/coap/coap-example-server/resources/res-light.c diff --git a/examples/coap/resources/res-mirror.c b/examples/coap/coap-example-server/resources/res-mirror.c similarity index 91% rename from examples/coap/resources/res-mirror.c rename to examples/coap/coap-example-server/resources/res-mirror.c index 1ba948b0d..619ed08a7 100644 --- a/examples/coap/resources/res-mirror.c +++ b/examples/coap/coap-example-server/resources/res-mirror.c @@ -41,17 +41,10 @@ #include "coap-engine.h" #include "coap.h" -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) -#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) -#else -#define PRINTF(...) -#define PRINT6ADDR(addr) -#define PRINTLLADDR(addr) -#endif +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "App" +#define LOG_LEVEL LOG_LEVEL_APP static void res_any_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -158,7 +151,7 @@ res_any_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff } coap_set_payload(response, buffer, strpos); - PRINTF("/mirror options received: %s\n", buffer); + LOG_DBG("/mirror options received: %s\n", buffer); /* Set dummy header options for response. Like getters, some setters are not implemented for HTTP and have no effect. */ coap_set_header_content_format(response, TEXT_PLAIN); diff --git a/examples/coap/resources/res-push.c b/examples/coap/coap-example-server/resources/res-push.c similarity index 100% rename from examples/coap/resources/res-push.c rename to examples/coap/coap-example-server/resources/res-push.c diff --git a/examples/coap/resources/res-radio.c b/examples/coap/coap-example-server/resources/res-radio.c similarity index 100% rename from examples/coap/resources/res-radio.c rename to examples/coap/coap-example-server/resources/res-radio.c diff --git a/examples/coap/resources/res-separate.c b/examples/coap/coap-example-server/resources/res-separate.c similarity index 100% rename from examples/coap/resources/res-separate.c rename to examples/coap/coap-example-server/resources/res-separate.c diff --git a/examples/coap/resources/res-sht11.c b/examples/coap/coap-example-server/resources/res-sht11.c similarity index 100% rename from examples/coap/resources/res-sht11.c rename to examples/coap/coap-example-server/resources/res-sht11.c diff --git a/examples/coap/resources/res-sub.c b/examples/coap/coap-example-server/resources/res-sub.c similarity index 100% rename from examples/coap/resources/res-sub.c rename to examples/coap/coap-example-server/resources/res-sub.c diff --git a/examples/coap/resources/res-temperature.c b/examples/coap/coap-example-server/resources/res-temperature.c similarity index 100% rename from examples/coap/resources/res-temperature.c rename to examples/coap/coap-example-server/resources/res-temperature.c diff --git a/examples/coap/resources/res-toggle.c b/examples/coap/coap-example-server/resources/res-toggle.c similarity index 100% rename from examples/coap/resources/res-toggle.c rename to examples/coap/coap-example-server/resources/res-toggle.c diff --git a/examples/coap/coap-plugtest-server/Makefile b/examples/coap/coap-plugtest-server/Makefile new file mode 100644 index 000000000..ee3bc511b --- /dev/null +++ b/examples/coap/coap-plugtest-server/Makefile @@ -0,0 +1,14 @@ +CONTIKI_PROJECT = coap-plugtest-server +all: $(CONTIKI_PROJECT) + +# Only intended for native +PLATFORMS_ONLY = native + +# Include the CoAP implementation +MODULES += os/net/app-layer/coap + +# Include CoAP resources +MODULES_REL += ./resources + +CONTIKI=../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/coap/plugtest-server.c b/examples/coap/coap-plugtest-server/coap-plugtest-server.c similarity index 91% rename from examples/coap/plugtest-server.c rename to examples/coap/coap-plugtest-server/coap-plugtest-server.c index 7ca53bc2d..4b6c6d557 100644 --- a/examples/coap/plugtest-server.c +++ b/examples/coap/coap-plugtest-server/coap-plugtest-server.c @@ -45,7 +45,11 @@ #include "coap-transactions.h" #include "coap-separate.h" #include "coap-engine.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST /* * Resources to be activated need to be imported through the extern keyword. @@ -80,19 +84,7 @@ PROCESS_THREAD(plugtest_server, ev, data) { PROCESS_BEGIN(); - PRINTF("ETSI IoT CoAP Plugtests Server\n"); - -#ifdef RF_CHANNEL - PRINTF("RF channel: %u\n", RF_CHANNEL); -#endif -#ifdef IEEE802154_PANID - PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); -#endif - - PRINTF("uIP buffer: %u\n", UIP_BUFSIZE); - PRINTF("LL header: %u\n", UIP_LLH_LEN); - PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); - PRINTF("REST max chunk: %u\n", REST_MAX_CHUNK_SIZE); + LOG_INFO("ETSI IoT CoAP Plugtests Server\n"); /* Initialize the REST engine. */ coap_engine_init(); diff --git a/examples/coap/plugtest.h b/examples/coap/coap-plugtest-server/project-conf.h similarity index 88% rename from examples/coap/plugtest.h rename to examples/coap/coap-plugtest-server/project-conf.h index dff97282f..c327bc047 100644 --- a/examples/coap/plugtest.h +++ b/examples/coap/coap-plugtest-server/project-conf.h @@ -36,20 +36,10 @@ * Matthias Kovatsch */ -#ifndef PLUGTEST_H_ -#define PLUGTEST_H_ +#ifndef __PROJECT_CONF_H__ +#define __PROJECT_CONF_H__ -#if !defined(CONTIKI_TARGET_NATIVE) -#warning "Should only be compiled for native!" -#endif - -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif +#define LOG_LEVEL_PLUGTEST LOG_LEVEL_DBG /* double expansion */ #define TO_STRING2(x) # x @@ -59,4 +49,4 @@ #define MAX_PLUGFEST_BODY 2048 #define CHUNKS_TOTAL 2012 -#endif /* PLUGTEST_H_ */ +#endif /* __PROJECT_CONF_H__ */ diff --git a/examples/coap/coap-plugtest-server/resources/res-mirror.c b/examples/coap/coap-plugtest-server/resources/res-mirror.c new file mode 100644 index 000000000..ea9ddd3ad --- /dev/null +++ b/examples/coap/coap-plugtest-server/resources/res-mirror.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include +#include +#include "coap-engine.h" +#include "coap.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST + +static void res_any_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* This resource mirrors the incoming request. It shows how to access the options and how to set them for the response. */ +RESOURCE(res_mirror, + "title=\"Returns your decoded message\";rt=\"Debug\"", + res_any_handler, + res_any_handler, + res_any_handler, + res_any_handler); + +static void +res_any_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* The ETag and Token is copied to the header. */ + uint8_t opaque[] = { 0x0A, 0xBC, 0xDE }; + + /* Strings are not copied, so use static string buffers or strings in .text memory (char *str = "string in .text";). */ + static char location[] = { '/', 'f', '/', 'a', '?', 'k', '&', 'e', 0 }; + + /* No default my be assumed for the Content-Format. (Unsigned -1 means all bits set.) */ + unsigned int content_format = -1; + + /* The other getters copy the value (or string/array pointer) to the given pointers and return 1 for success or the length of strings/arrays. */ + uint32_t longint = 0; + const char *str = NULL; + const uint8_t *bytes = NULL; + uint32_t block_num = 0; + uint8_t block_more = 0; + uint16_t block_size = 0; + int len = 0; + + /* Mirror the received header options in the response payload. Unsupported getters (e.g., rest_get_header_observe() with HTTP) will return 0. */ + + int strpos = 0; + /* snprintf() counts the terminating '\0' to the size parameter. + * The additional byte is taken care of by allocating REST_MAX_CHUNK_SIZE+1 bytes in the REST framework. + * Add +1 to fill the complete buffer, as the payload does not need a terminating '\0'. */ + if(coap_get_header_content_format(request, &content_format)) { + strpos += snprintf((char *)buffer, REST_MAX_CHUNK_SIZE + 1, "CF %u\n", content_format); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_accept(request, &content_format))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "Ac %u\n", content_format); + /* Some getters such as for ETag or Location are omitted, as these options should not appear in a request. + * Max-Age might appear in HTTP requests or used for special purposes in CoAP. */ + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_get_header_max_age(request, &longint)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "MA %lu\n", (unsigned long) longint); + /* For HTTP this is the Length option, for CoAP it is the Size option. */ + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_get_header_size1(request, &longint)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "SZ %lu\n", (unsigned long) longint); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_uri_host(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "UH %.*s\n", len, str); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_uri_path(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "UP %.*s\n", len, str); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_uri_query(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "UQ %.*s\n", len, str); + /* Undefined request options for debugging: actions not required for normal RESTful Web service. */ + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_path(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "LP %.*s\n", len, str); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_query(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "LQ %.*s\n", len, str); + /* CoAP-specific example: actions not required for normal RESTful Web service. */ + } + coap_message_t *const coap_pkt = (coap_message_t *)request; + + if(strpos <= REST_MAX_CHUNK_SIZE && coap_pkt->token_len > 0) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "To 0x"); + int index = 0; + for(index = 0; index < coap_pkt->token_len; ++index) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "%02X", coap_pkt->token[index]); + } + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "\n"); + } + + if(strpos <= REST_MAX_CHUNK_SIZE && coap_is_option(coap_pkt, COAP_OPTION_OBSERVE)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "Ob %lu\n", (unsigned long) coap_pkt->observe); + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_is_option(coap_pkt, COAP_OPTION_ETAG)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "ET 0x"); + int index = 0; + for(index = 0; index < coap_pkt->etag_len; ++index) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "%02X", coap_pkt->etag[index]); + } + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "\n"); + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_get_header_block2(request, &block_num, &block_more, &block_size, NULL)) { /* This getter allows NULL pointers to get only a subset of the block parameters. */ + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "B2 %lu%s (%u)\n", (unsigned long) block_num, block_more ? "+" : "", block_size); + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_get_header_block1(request, &block_num, &block_more, &block_size, NULL)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "B1 %lu%s (%u)\n", (unsigned long) block_num, block_more ? "+" : "", block_size); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_payload(request, &bytes))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "%.*s", len, bytes); + } + if(strpos >= REST_MAX_CHUNK_SIZE) { + buffer[REST_MAX_CHUNK_SIZE - 1] = 0xBB; /* '»' to indicate truncation */ + } + coap_set_payload(response, buffer, strpos); + + LOG_DBG("/mirror options received: %s\n", buffer); + + /* Set dummy header options for response. Like getters, some setters are not implemented for HTTP and have no effect. */ + coap_set_header_content_format(response, TEXT_PLAIN); + coap_set_header_max_age(response, 17); /* For HTTP, browsers will not re-request the page for 17 seconds. */ + coap_set_header_etag(response, opaque, 2); + coap_set_header_location_path(response, location); /* Initial slash is omitted by framework */ + coap_set_header_size1(response, strpos); /* For HTTP, browsers will not re-request the page for 10 s. CoAP action depends on the client. */ + +/* CoAP-specific example: actions not required for normal RESTful Web service. */ + coap_set_header_uri_host(response, "tiki"); + coap_set_header_observe(response, 10); + coap_set_header_proxy_uri(response, "ftp://x"); + coap_set_header_block2(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */ + coap_set_header_block1(response, 23, 0, 16); + coap_set_header_accept(response, TEXT_PLAIN); + coap_set_header_if_none_match(response); +} diff --git a/examples/coap/resources-plugtest/res-plugtest-create1.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-create1.c similarity index 94% rename from examples/coap/resources-plugtest/res-plugtest-create1.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-create1.c index 50f48a09e..fe57e4961 100644 --- a/examples/coap/resources-plugtest/res-plugtest-create1.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-create1.c @@ -39,7 +39,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_delete_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -56,7 +60,7 @@ static uint8_t create1_exists = 0; static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - PRINTF("/create1 PUT"); + LOG_DBG("/create1 PUT"); if(coap_get_header_if_none_match(request)) { if(!create1_exists) { @@ -73,7 +77,7 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff static void res_delete_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - PRINTF("/create1 DELETE "); + LOG_DBG("/create1 DELETE "); coap_set_status_code(response, DELETED_2_02); create1_exists = 0; diff --git a/examples/coap/resources-plugtest/res-plugtest-create2.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-create2.c similarity index 94% rename from examples/coap/resources-plugtest/res-plugtest-create2.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-create2.c index 169f47812..b4520d672 100644 --- a/examples/coap/resources-plugtest/res-plugtest-create2.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-create2.c @@ -39,7 +39,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -53,7 +57,7 @@ RESOURCE(res_plugtest_create2, static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - PRINTF("/create2 "); + LOG_DBG("/create2 "); coap_set_status_code(response, CREATED_2_01); coap_set_header_location_path(response, "/location1/location2/location3"); diff --git a/examples/coap/resources-plugtest/res-plugtest-create3.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-create3.c similarity index 94% rename from examples/coap/resources-plugtest/res-plugtest-create3.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-create3.c index 178a0089e..b78fca67e 100644 --- a/examples/coap/resources-plugtest/res-plugtest-create3.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-create3.c @@ -39,7 +39,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_delete_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -56,7 +60,7 @@ static uint8_t create3_exists = 0; static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - PRINTF("/create3 PUT "); + LOG_DBG("/create3 PUT "); if(coap_get_header_if_none_match(request)) { if(!create3_exists) { @@ -73,7 +77,7 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff static void res_delete_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - PRINTF("/create3 DELETE "); + LOG_DBG("/create3 DELETE "); coap_set_status_code(response, DELETED_2_02); create3_exists = 0; diff --git a/examples/coap/resources-plugtest/res-plugtest-large-create.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-large-create.c similarity index 96% rename from examples/coap/resources-plugtest/res-plugtest-large-create.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-large-create.c index 78d21b69b..923702f51 100644 --- a/examples/coap/resources-plugtest/res-plugtest-large-create.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-large-create.c @@ -39,7 +39,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); diff --git a/examples/coap/resources-plugtest/res-plugtest-large-update.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-large-update.c similarity index 97% rename from examples/coap/resources-plugtest/res-plugtest-large-update.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-large-update.c index a79978be1..289fbdfdf 100644 --- a/examples/coap/resources-plugtest/res-plugtest-large-update.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-large-update.c @@ -41,7 +41,11 @@ #include "sys/cc.h" #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); diff --git a/examples/coap/resources-plugtest/res-plugtest-large.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-large.c similarity index 96% rename from examples/coap/resources-plugtest/res-plugtest-large.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-large.c index f828e4dbe..850f88461 100644 --- a/examples/coap/resources-plugtest/res-plugtest-large.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-large.c @@ -40,7 +40,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); diff --git a/examples/coap/resources-plugtest/res-plugtest-links.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-links.c similarity index 95% rename from examples/coap/resources-plugtest/res-plugtest-links.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-links.c index 99315a17f..3bbd2a062 100644 --- a/examples/coap/resources-plugtest/res-plugtest-links.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-links.c @@ -39,7 +39,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); diff --git a/examples/coap/resources-plugtest/res-plugtest-locquery.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-locquery.c similarity index 95% rename from examples/coap/resources-plugtest/res-plugtest-locquery.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-locquery.c index e93ef8b65..e7163e8b1 100644 --- a/examples/coap/resources-plugtest/res-plugtest-locquery.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-locquery.c @@ -39,7 +39,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -53,11 +57,9 @@ RESOURCE(res_plugtest_locquery, static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { -#if DEBUG coap_message_t *const coap_req = (coap_message_t *)request; -#endif - PRINTF( + LOG_DBG( "/location-query POST (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); coap_set_status_code(response, CREATED_2_01); diff --git a/examples/coap/resources-plugtest/res-plugtest-longpath.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-longpath.c similarity index 91% rename from examples/coap/resources-plugtest/res-plugtest-longpath.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-longpath.c index 7a1271321..990ad2677 100644 --- a/examples/coap/resources-plugtest/res-plugtest-longpath.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-longpath.c @@ -41,7 +41,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -57,7 +61,7 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff { coap_message_t *const coap_req = (coap_message_t *)request; - PRINTF("/seg1/seg2/seg3 GET "); + LOG_DBG("/seg1/seg2/seg3 GET "); /* Code 2.05 CONTENT is default. */ coap_set_header_content_format(response, TEXT_PLAIN); coap_set_payload( @@ -66,5 +70,5 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); - PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + LOG_DBG_("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); } diff --git a/examples/coap/resources-plugtest/res-plugtest-multi.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-multi.c similarity index 91% rename from examples/coap/resources-plugtest/res-plugtest-multi.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-multi.c index f0a388430..9606d91a6 100644 --- a/examples/coap/resources-plugtest/res-plugtest-multi.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-multi.c @@ -40,7 +40,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -59,7 +63,7 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff unsigned int accept = -1; coap_get_header_accept(request, &accept); - PRINTF("/multi-format GET (%s %u) ", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + LOG_DBG("/multi-format GET (%s %u) ", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); if(accept == -1 || accept == TEXT_PLAIN) { coap_set_header_content_format(response, TEXT_PLAIN); @@ -69,7 +73,7 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u%s", coap_req->type, coap_req->code, coap_req->mid, accept != -1 ? "\nAccept: 0" : "")); - PRINTF("PLAIN\n"); + LOG_DBG_("PLAIN\n"); } else if(accept == APPLICATION_XML) { coap_set_header_content_format(response, APPLICATION_XML); coap_set_payload( @@ -78,11 +82,11 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "", coap_req->type, coap_req->code, coap_req->mid, accept)); - PRINTF("XML\n"); + LOG_DBG_("XML\n"); } else { coap_set_status_code(response, NOT_ACCEPTABLE_4_06); const char *msg = "Supporting content-types text/plain and application/xml"; coap_set_payload(response, msg, strlen(msg)); - PRINTF("ERROR\n"); + LOG_DBG_("ERROR\n"); } } diff --git a/examples/coap/resources-plugtest/res-plugtest-obs.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-obs.c similarity index 94% rename from examples/coap/resources-plugtest/res-plugtest-obs.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-obs.c index d60aaec04..7d191e751 100644 --- a/examples/coap/resources-plugtest/res-plugtest-obs.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-obs.c @@ -41,7 +41,11 @@ #include "coap-engine.h" #include "coap.h" #include "coap-observe.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -67,7 +71,7 @@ static char obs_status = 0; static void obs_purge_list() { - PRINTF("### SERVER ACTION ### Purging obs list"); + LOG_DBG("### SERVER ACTION ### Purging obs list\n"); coap_remove_observer_by_uri(NULL, res_plugtest_obs.url); } static void @@ -75,7 +79,7 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff { /* Keep server log clean from ticking events */ if(request != NULL) { - PRINTF("/obs GET\n"); + LOG_DBG("/obs GET\n"); } coap_set_header_content_format(response, obs_format); coap_set_header_max_age(response, 5); @@ -98,7 +102,7 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff coap_get_header_content_format(request, &ct); - PRINTF("/obs PUT\n"); + LOG_DBG("/obs PUT\n"); if(ct != obs_format) { obs_status = 1; @@ -115,7 +119,7 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff static void res_delete_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - PRINTF("/obs DELETE\n"); + LOG_DBG("/obs DELETE\n"); obs_status = 2; @@ -130,14 +134,12 @@ res_periodic_handler() { ++obs_counter; - /* PRINTF("TICK %u for /%s\n", obs_counter, r->url); */ - if(obs_status == 1) { /* Notify the registered observers with the given message type, observe option, and payload. */ coap_notify_observers(&res_plugtest_obs); - PRINTF("######### sending 5.00\n"); + LOG_DBG("######### sending 5.00\n"); obs_purge_list(); } else if(obs_status == 2) { diff --git a/examples/coap/resources-plugtest/res-plugtest-path.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-path.c similarity index 96% rename from examples/coap/resources-plugtest/res-plugtest-path.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-path.c index fac05ccb0..767609f09 100644 --- a/examples/coap/resources-plugtest/res-plugtest-path.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-path.c @@ -40,7 +40,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); diff --git a/examples/coap/resources-plugtest/res-plugtest-query.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-query.c similarity index 94% rename from examples/coap/resources-plugtest/res-plugtest-query.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-query.c index 10df145b3..1080d3162 100644 --- a/examples/coap/resources-plugtest/res-plugtest-query.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-query.c @@ -40,7 +40,11 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -58,11 +62,11 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff int len = 0; const char *query = NULL; - PRINTF( + LOG_DBG( "/query GET (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); if((len = coap_get_header_uri_query(request, &query))) { - PRINTF("Query: %.*s\n", len, query); + LOG_DBG("Query: %.*s\n", len, query); /* Code 2.05 CONTENT is default. */ } coap_set_header_content_format(response, diff --git a/examples/coap/resources-plugtest/res-plugtest-separate.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-separate.c similarity index 93% rename from examples/coap/resources-plugtest/res-plugtest-separate.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-separate.c index 16aa267ce..c0ae81d11 100644 --- a/examples/coap/resources-plugtest/res-plugtest-separate.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-separate.c @@ -42,7 +42,11 @@ #include "coap.h" #include "coap-transactions.h" #include "coap-separate.h" -#include "plugtest.h" + +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_resume_handler(void); @@ -72,12 +76,12 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff { coap_message_t *const coap_req = (coap_message_t *)request; - PRINTF("/separate "); + LOG_DBG("/separate "); if(separate_active) { - PRINTF("REJECTED "); + LOG_DBG_("REJECTED "); coap_separate_reject(); } else { - PRINTF("STORED "); + LOG_DBG_("STORED "); separate_active = 1; /* Take over and skip response by engine. */ @@ -89,17 +93,17 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff coap_req->mid); } - PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + LOG_DBG_("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); } static void res_resume_handler() { if(separate_active) { - PRINTF("/separate "); + LOG_DBG("/separate "); coap_transaction_t *transaction = NULL; if((transaction = coap_new_transaction(separate_store->request_metadata.mid, &separate_store->request_metadata.endpoint))) { - PRINTF( + LOG_DBG_( "RESPONSE (%s %u)\n", separate_store->request_metadata.type == COAP_TYPE_CON ? "CON" : "NON", separate_store->request_metadata.mid); coap_message_t response[1]; /* This way the message can be treated as pointer as usual. */ @@ -127,7 +131,7 @@ res_resume_handler() separate_active = 0; } else { - PRINTF("ERROR (transaction)\n"); + LOG_DBG_("ERROR (transaction)\n"); } } /* if (separate_active) */ } diff --git a/examples/coap/resources-plugtest/res-plugtest-test.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-test.c similarity index 81% rename from examples/coap/resources-plugtest/res-plugtest-test.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-test.c index f7ac97c83..d02b3026d 100644 --- a/examples/coap/resources-plugtest/res-plugtest-test.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-test.c @@ -40,9 +40,13 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" #include "random.h" +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST + static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -68,7 +72,7 @@ test_update_etag() } test_change = 0; - PRINTF("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", test_etag_len, test_etag[0], test_etag[1], test_etag[2], test_etag[3], test_etag[4], test_etag[5], test_etag[6], test_etag[7]); + LOG_DBG("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", test_etag_len, test_etag[0], test_etag[1], test_etag[2], test_etag[3], test_etag[4], test_etag[5], test_etag[6], test_etag[7]); } static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) @@ -78,17 +82,17 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff if(test_change) { test_update_etag(); } - PRINTF("/test GET (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + LOG_DBG("/test GET (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); if((len = coap_get_header_etag(request, &bytes)) > 0 && len == test_etag_len && memcmp(test_etag, bytes, len) == 0) { - PRINTF("validate "); + LOG_DBG("validate\n"); coap_set_status_code(response, VALID_2_03); coap_set_header_etag(response, test_etag, test_etag_len); test_change = 1; - PRINTF("### SERVER ACTION ### Resource will change\n"); + LOG_DBG("### SERVER ACTION ### Resource will change\n"); } else { /* Code 2.05 CONTENT is default. */ coap_set_header_content_format(response, TEXT_PLAIN); @@ -103,32 +107,28 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff static void res_post_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { -#if DEBUG - coap_message_t *const coap_req = (coap_message_t *)request; - PRINTF("/test POST (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); -#endif + coap_message_t *const coap_req = (coap_message_t *)request; + LOG_DBG("/test POST (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); coap_set_status_code(response, CREATED_2_01); coap_set_header_location_path(response, "/location1/location2/location3"); } static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { -#if DEBUG coap_message_t *const coap_req = (coap_message_t *)request; - PRINTF("/test PUT (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); -#endif + LOG_DBG("/test PUT (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); if(coap_get_header_if_none_match(request)) { if(test_none_match_okay) { coap_set_status_code(response, CREATED_2_01); test_none_match_okay = 0; - PRINTF("### SERVER ACTION ### If-None-Match will FAIL\n"); + LOG_DBG("### SERVER ACTION ### If-None-Match will FAIL\n"); } else { coap_set_status_code(response, PRECONDITION_FAILED_4_12); test_none_match_okay = 1; - PRINTF("### SERVER ACTION ### If-None-Match will SUCCEED\n"); + LOG_DBG("### SERVER ACTION ### If-None-Match will SUCCEED\n"); } } else if(((len = coap_get_header_if_match(request, &bytes)) > 0 && (len == test_etag_len @@ -141,12 +141,12 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff if(len > 0) { test_change = 1; - PRINTF("### SERVER ACTION ### Resource will change\n"); + LOG_DBG("### SERVER ACTION ### Resource will change\n"); } } else { - PRINTF("Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", - len, - test_etag_len, + LOG_DBG("Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + (unsigned)len, + (unsigned)test_etag_len, bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], test_etag[0], test_etag[1], test_etag[2], test_etag[3], test_etag[4], test_etag[5], test_etag[6], test_etag[7]); @@ -156,9 +156,7 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff static void res_delete_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { -#if DEBUG coap_message_t *const coap_req = (coap_message_t *)request; - PRINTF("/test DELETE (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); -#endif + LOG_DBG("/test DELETE (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); coap_set_status_code(response, DELETED_2_02); } diff --git a/examples/coap/resources-plugtest/res-plugtest-validate.c b/examples/coap/coap-plugtest-server/resources/res-plugtest-validate.c similarity index 87% rename from examples/coap/resources-plugtest/res-plugtest-validate.c rename to examples/coap/coap-plugtest-server/resources/res-plugtest-validate.c index 30d97e727..7a5920c2b 100644 --- a/examples/coap/resources-plugtest/res-plugtest-validate.c +++ b/examples/coap/coap-plugtest-server/resources/res-plugtest-validate.c @@ -40,9 +40,13 @@ #include #include "coap-engine.h" #include "coap.h" -#include "plugtest.h" #include "random.h" +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "Plugtest" +#define LOG_LEVEL LOG_LEVEL_PLUGTEST + static void res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); @@ -70,7 +74,7 @@ validate_update_etag() } validate_change = 0; - PRINTF("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + LOG_DBG("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", validate_etag_len, validate_etag[0], validate_etag[1], validate_etag[2], validate_etag[3], validate_etag[4], validate_etag[5], validate_etag[6], validate_etag[7]); } static void @@ -81,17 +85,17 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff if(validate_change) { validate_update_etag(); } - PRINTF("/validate GET"); - PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + LOG_DBG("/validate GET"); + LOG_DBG_("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); if((len = coap_get_header_etag(request, &bytes)) > 0 && len == validate_etag_len && memcmp(validate_etag, bytes, len) == 0) { - PRINTF("validate "); + LOG_DBG("validate\n"); coap_set_status_code(response, VALID_2_03); coap_set_header_etag(response, validate_etag, validate_etag_len); validate_change = 1; - PRINTF("### SERVER ACTION ### Resouce will change\n"); + LOG_DBG("### SERVER ACTION ### Resouce will change\n"); } else { /* Code 2.05 CONTENT is default. */ coap_set_header_content_format(response, TEXT_PLAIN); @@ -108,12 +112,10 @@ res_get_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff static void res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { -#if DEBUG coap_message_t *const coap_req = (coap_message_t *)request; -#endif - PRINTF("/validate PUT "); - PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + LOG_DBG("/validate PUT "); + LOG_DBG_("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); if(((len = coap_get_header_if_match(request, &bytes)) > 0 && (len == validate_etag_len @@ -126,13 +128,13 @@ res_put_handler(coap_message_t *request, coap_message_t *response, uint8_t *buff if(len > 0) { validate_change = 1; - PRINTF("### SERVER ACTION ### Resouce will change\n"); + LOG_DBG("### SERVER ACTION ### Resouce will change\n"); } } else { - PRINTF( - "Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X] ", - len, - validate_etag_len, + LOG_DBG( + "Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + (unsigned)len, + (unsigned)validate_etag_len, bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], validate_etag[0], validate_etag[1], validate_etag[2], validate_etag[3], validate_etag[4], validate_etag[5], validate_etag[6], validate_etag[7]); From 99acfc1ab3cad7526c5c3451663f8b9859a600b0 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 13 Apr 2018 09:14:52 -0700 Subject: [PATCH 075/129] CI: added tests for examples under examples/coap --- tests/01-compile-base/Makefile | 3 +++ tests/02-compile-arm-ports-01/Makefile | 3 ++- tests/03-compile-arm-ports-02/Makefile | 3 ++- tests/04-compile-nxp-ports/Makefile | 2 ++ tests/17-tun-rpl-br/06-native-coap.sh | 8 ++++---- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index 1d09fd3a0..5dfb3f149 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -23,6 +23,9 @@ slip-radio/sky \ libs/ipv6-hooks/sky \ nullnet/native \ mqtt-client/native \ +coap/coap-example-client/native \ +coap/coap-example-server/native \ +coap/coap-plugtest-server/native \ TOOLS= diff --git a/tests/02-compile-arm-ports-01/Makefile b/tests/02-compile-arm-ports-01/Makefile index 77cce805b..5e73c4ecb 100644 --- a/tests/02-compile-arm-ports-01/Makefile +++ b/tests/02-compile-arm-ports-01/Makefile @@ -39,7 +39,8 @@ mqtt-client/cc2538dk \ storage/cfs-coffee/cc2538dk \ sensniff/cc2538dk \ rpl-udp/cc2538dk \ -coap/cc2538dk \ +coap/coap-example-client/cc2538dk \ +coap/coap-example-server/cc2538dk \ slip-radio/cc2538dk \ lwm2m-ipso-objects/cc2538dk \ multicast/cc2538dk \ diff --git a/tests/03-compile-arm-ports-02/Makefile b/tests/03-compile-arm-ports-02/Makefile index a4e1947e8..db016afaa 100644 --- a/tests/03-compile-arm-ports-02/Makefile +++ b/tests/03-compile-arm-ports-02/Makefile @@ -12,7 +12,8 @@ platform-specific/zoul/rev-b/zoul:BOARD=remote-revb \ platform-specific/zoul/at-test/zoul \ platform-specific/zoul/rtcc/zoul \ platform-specific/zoul/zoul \ -coap/zoul \ +coap/coap-example-client/zoul \ +coap/coap-example-server/zoul \ multicast/zoul \ lwm2m-ipso-objects/zoul \ lwm2m-ipso-objects/zoul:MAKE_WITH_DTLS=1 \ diff --git a/tests/04-compile-nxp-ports/Makefile b/tests/04-compile-nxp-ports/Makefile index cec1f91af..214bced26 100644 --- a/tests/04-compile-nxp-ports/Makefile +++ b/tests/04-compile-nxp-ports/Makefile @@ -12,6 +12,8 @@ platform-specific/jn516x/rpl/coap-dr1199-node/jn516x \ platform-specific/jn516x/tsch/simple-sensor-network/node/jn516x \ platform-specific/jn516x/tsch/tx-power-verification/node/jn516x \ platform-specific/jn516x/tsch/uart1-test-node/jn516x \ +coap/coap-example-client/jn516x \ +coap/coap-example-server/jn516x \ sensniff/jn516x \ rpl-border-router/jn516x \ 6tisch/simple-node/jn516x \ diff --git a/tests/17-tun-rpl-br/06-native-coap.sh b/tests/17-tun-rpl-br/06-native-coap.sh index 16dd8aab7..88627ec19 100755 --- a/tests/17-tun-rpl-br/06-native-coap.sh +++ b/tests/17-tun-rpl-br/06-native-coap.sh @@ -12,8 +12,8 @@ declare -i TESTCOUNT=0 # Starting Contiki-NG native node echo "Starting native CoAP server" -make -C $CONTIKI/examples/coap > make.log 2> make.err -sudo $CONTIKI/examples/coap/coap-example-server.native > node.log 2> node.err & +make -C $CONTIKI/examples/coap/coap-example-server > make.log 2> make.err +sudo $CONTIKI/examples/coap/coap-example-server/coap-example-server.native > node.log 2> node.err & CPID=$! sleep 2 @@ -41,7 +41,7 @@ sleep 2 pgrep coap-example | sudo xargs kill -9 if [ $TESTCOUNT -eq $OKCOUNT ] ; then - printf "%-32s TEST OK %3d/%d\n" "$BASENAME" "$OKCOUNT" "$TESTCOUNT" > $BASENAME.testlog; + printf "%-32s TEST OK %3d/%d\n" "$BASENAME" "$OKCOUNT" "$TESTCOUNT" | tee $BASENAME.testlog; else echo "==== make.log ====" ; cat make.log; echo "==== make.err ====" ; cat make.err; @@ -49,7 +49,7 @@ else echo "==== node.err ====" ; cat node.err; echo "==== $BASENAME.log ====" ; cat $BASENAME.log; - printf "%-32s TEST FAIL %3d/%d\n" "$BASENAME" "$OKCOUNT" "$TESTCOUNT" > $BASENAME.testlog; + printf "%-32s TEST FAIL %3d/%d\n" "$BASENAME" "$OKCOUNT" "$TESTCOUNT" | tee $BASENAME.testlog; fi rm -f make.log make.err node.log node.err coap.log From d59db9a94d900ecdc76322708a724a8895ad6386 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 20 Apr 2018 05:29:48 -0700 Subject: [PATCH 076/129] Examples: consistently use PROJECT_CONF_H --- examples/6tisch/6p-packet/project-conf.h | 6 +++--- examples/6tisch/etsi-plugtest-2017/project-conf.h | 6 +++--- examples/6tisch/simple-node/project-conf.h | 6 +++--- examples/6tisch/sixtop/project-conf.h | 6 +++--- examples/coap/coap-example-client/project-conf.h | 6 +++--- examples/coap/coap-example-server/project-conf.h | 6 +++--- examples/coap/coap-plugtest-server/project-conf.h | 6 +++--- examples/libs/stack-check/project-conf.h | 6 +++--- .../jn516x/rpl/coap-dongle-node/project-conf.h | 6 +++--- .../jn516x/rpl/coap-dr1175-node/project-conf.h | 6 +++--- .../jn516x/rpl/coap-dr1199-node/project-conf.h | 6 +++--- examples/platform-specific/jn516x/rpl/node/project-conf.h | 6 +++--- .../jn516x/tsch/simple-sensor-network/node/project-conf.h | 6 +++--- .../jn516x/tsch/tx-power-verification/node/project-conf.h | 6 +++--- .../jn516x/tsch/uart1-test-node/project-conf.h | 6 +++--- tests/07-simulation-base/code-ringbufindex/project-conf.h | 6 +++--- tests/07-simulation-base/code-slip-radio/project-conf.h | 6 +++--- tests/13-ieee802154/code-6tisch/project-conf.h | 6 +++--- tests/13-ieee802154/code-flush-nbr-queue/project-conf.h | 6 +++--- tests/13-ieee802154/code-panid-handling/project-conf.h | 6 +++--- 20 files changed, 60 insertions(+), 60 deletions(-) diff --git a/examples/6tisch/6p-packet/project-conf.h b/examples/6tisch/6p-packet/project-conf.h index ece485a17..9771fe4b1 100644 --- a/examples/6tisch/6p-packet/project-conf.h +++ b/examples/6tisch/6p-packet/project-conf.h @@ -28,8 +28,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _PROJECT_CONF_H_ -#define _PROJECT_CONF_H_ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_ND6_SEND_RA 0 @@ -39,4 +39,4 @@ #define LOG_CONF_LEVEL_6TOP LOG_LEVEL_DBG -#endif /* _PROJECT_CONF_H_ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/6tisch/etsi-plugtest-2017/project-conf.h b/examples/6tisch/etsi-plugtest-2017/project-conf.h index 971f9020d..93c5925b6 100644 --- a/examples/6tisch/etsi-plugtest-2017/project-conf.h +++ b/examples/6tisch/etsi-plugtest-2017/project-conf.h @@ -32,8 +32,8 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ /* Set to enable TSCH security */ #ifndef WITH_SECURITY @@ -115,4 +115,4 @@ #define LOG_CONF_LEVEL_6TOP LOG_LEVEL_DBG #define TSCH_LOG_CONF_PER_SLOT 1 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/6tisch/simple-node/project-conf.h b/examples/6tisch/simple-node/project-conf.h index f77e63706..3771fb50f 100644 --- a/examples/6tisch/simple-node/project-conf.h +++ b/examples/6tisch/simple-node/project-conf.h @@ -32,8 +32,8 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ /* Set to enable TSCH security */ #ifndef WITH_SECURITY @@ -78,4 +78,4 @@ #define LOG_CONF_LEVEL_FRAMER LOG_LEVEL_DBG #define TSCH_LOG_CONF_PER_SLOT 1 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/6tisch/sixtop/project-conf.h b/examples/6tisch/sixtop/project-conf.h index 7f416342e..5235353c2 100755 --- a/examples/6tisch/sixtop/project-conf.h +++ b/examples/6tisch/sixtop/project-conf.h @@ -28,8 +28,8 @@ * */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ /* Set to enable TSCH security */ #ifndef WITH_SECURITY @@ -103,4 +103,4 @@ #endif /* CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL \ || CONTIKI_TARGET_OPENMOTE_CC2538 */ -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/coap/coap-example-client/project-conf.h b/examples/coap/coap-example-client/project-conf.h index 783e3e84b..7247ea08c 100644 --- a/examples/coap/coap-example-client/project-conf.h +++ b/examples/coap/coap-example-client/project-conf.h @@ -36,12 +36,12 @@ * Matthias Kovatsch */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define LOG_LEVEL_APP LOG_LEVEL_DBG /* Enable client-side support for COAP observe */ #define COAP_OBSERVE_CLIENT 1 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/coap/coap-example-server/project-conf.h b/examples/coap/coap-example-server/project-conf.h index 436da55a5..eeec89082 100644 --- a/examples/coap/coap-example-server/project-conf.h +++ b/examples/coap/coap-example-server/project-conf.h @@ -36,9 +36,9 @@ * Matthias Kovatsch */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define LOG_LEVEL_APP LOG_LEVEL_DBG -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/coap/coap-plugtest-server/project-conf.h b/examples/coap/coap-plugtest-server/project-conf.h index c327bc047..5c86ae985 100644 --- a/examples/coap/coap-plugtest-server/project-conf.h +++ b/examples/coap/coap-plugtest-server/project-conf.h @@ -36,8 +36,8 @@ * Matthias Kovatsch */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define LOG_LEVEL_PLUGTEST LOG_LEVEL_DBG @@ -49,4 +49,4 @@ #define MAX_PLUGFEST_BODY 2048 #define CHUNKS_TOTAL 2012 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/libs/stack-check/project-conf.h b/examples/libs/stack-check/project-conf.h index 2509dd080..a9cbe2265 100644 --- a/examples/libs/stack-check/project-conf.h +++ b/examples/libs/stack-check/project-conf.h @@ -36,9 +36,9 @@ * */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define STACK_CHECK_CONF_ENABLED 1 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/rpl/coap-dongle-node/project-conf.h b/examples/platform-specific/jn516x/rpl/coap-dongle-node/project-conf.h index a46f32f1c..bb7d4d785 100644 --- a/examples/platform-specific/jn516x/rpl/coap-dongle-node/project-conf.h +++ b/examples/platform-specific/jn516x/rpl/coap-dongle-node/project-conf.h @@ -31,11 +31,11 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_TCP 0 #include "../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/rpl/coap-dr1175-node/project-conf.h b/examples/platform-specific/jn516x/rpl/coap-dr1175-node/project-conf.h index a46f32f1c..bb7d4d785 100644 --- a/examples/platform-specific/jn516x/rpl/coap-dr1175-node/project-conf.h +++ b/examples/platform-specific/jn516x/rpl/coap-dr1175-node/project-conf.h @@ -31,11 +31,11 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_TCP 0 #include "../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/rpl/coap-dr1199-node/project-conf.h b/examples/platform-specific/jn516x/rpl/coap-dr1199-node/project-conf.h index a46f32f1c..bb7d4d785 100644 --- a/examples/platform-specific/jn516x/rpl/coap-dr1199-node/project-conf.h +++ b/examples/platform-specific/jn516x/rpl/coap-dr1199-node/project-conf.h @@ -31,11 +31,11 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_TCP 0 #include "../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/rpl/node/project-conf.h b/examples/platform-specific/jn516x/rpl/node/project-conf.h index 9db6f0229..52adee3b9 100644 --- a/examples/platform-specific/jn516x/rpl/node/project-conf.h +++ b/examples/platform-specific/jn516x/rpl/node/project-conf.h @@ -32,9 +32,9 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #include "../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/project-conf.h b/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/project-conf.h index 360fdef25..65ddcef46 100644 --- a/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/project-conf.h +++ b/examples/platform-specific/jn516x/tsch/simple-sensor-network/node/project-conf.h @@ -32,12 +32,12 @@ * */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_TCP 0 #define UART_BAUD_RATE UART_RATE_115200 #include "../../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/tsch/tx-power-verification/node/project-conf.h b/examples/platform-specific/jn516x/tsch/tx-power-verification/node/project-conf.h index 0394b0ad5..94e17dc1c 100644 --- a/examples/platform-specific/jn516x/tsch/tx-power-verification/node/project-conf.h +++ b/examples/platform-specific/jn516x/tsch/tx-power-verification/node/project-conf.h @@ -31,12 +31,12 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_TCP 0 #define UART_BAUD_RATE UART_RATE_115200 #include "../../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/platform-specific/jn516x/tsch/uart1-test-node/project-conf.h b/examples/platform-specific/jn516x/tsch/uart1-test-node/project-conf.h index 373ea0f27..d833869bb 100644 --- a/examples/platform-specific/jn516x/tsch/uart1-test-node/project-conf.h +++ b/examples/platform-specific/jn516x/tsch/uart1-test-node/project-conf.h @@ -31,8 +31,8 @@ * \author Simon Duquennoy */ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UIP_CONF_TCP 0 @@ -46,4 +46,4 @@ #include "../common-conf.h" -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/tests/07-simulation-base/code-ringbufindex/project-conf.h b/tests/07-simulation-base/code-ringbufindex/project-conf.h index a7683dbb5..e745536d9 100644 --- a/tests/07-simulation-base/code-ringbufindex/project-conf.h +++ b/tests/07-simulation-base/code-ringbufindex/project-conf.h @@ -29,9 +29,9 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _PROJECT_CONF_H_ -#define _PROJECT_CONF_H_ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UNIT_TEST_PRINT_FUNCTION test_print_report -#endif /* !_PROJECT_CONF_H_ */ +#endif /* !PROJECT_CONF_H_ */ diff --git a/tests/07-simulation-base/code-slip-radio/project-conf.h b/tests/07-simulation-base/code-slip-radio/project-conf.h index 616601c1c..e8af03208 100644 --- a/tests/07-simulation-base/code-slip-radio/project-conf.h +++ b/tests/07-simulation-base/code-slip-radio/project-conf.h @@ -1,6 +1,6 @@ -#ifndef __PROJECT_CONF_H__ -#define __PROJECT_CONF_H__ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define RPL_CONF_DAO_ACK 1 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/tests/13-ieee802154/code-6tisch/project-conf.h b/tests/13-ieee802154/code-6tisch/project-conf.h index 657244d5a..acf60cbab 100644 --- a/tests/13-ieee802154/code-6tisch/project-conf.h +++ b/tests/13-ieee802154/code-6tisch/project-conf.h @@ -28,8 +28,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _PROJECT_CONF_H_ -#define _PROJECT_CONF_H_ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define SIXTOP_CONF_MAX_SCHEDULING_FUNCTIONS 2 @@ -52,4 +52,4 @@ /* Custom MAC layer */ #define NETSTACK_CONF_MAC test_mac_driver -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/tests/13-ieee802154/code-flush-nbr-queue/project-conf.h b/tests/13-ieee802154/code-flush-nbr-queue/project-conf.h index 6923ae6fb..039bc7c49 100644 --- a/tests/13-ieee802154/code-flush-nbr-queue/project-conf.h +++ b/tests/13-ieee802154/code-flush-nbr-queue/project-conf.h @@ -29,8 +29,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _PROJECT_CONF_H_ -#define _PROJECT_CONF_H_ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UNIT_TEST_PRINT_FUNCTION test_print_report @@ -41,4 +41,4 @@ #define TSCH_CONF_WITH_SIXTOP 1 -#endif /* __PROJECT_CONF_H__ */ +#endif /* PROJECT_CONF_H_ */ diff --git a/tests/13-ieee802154/code-panid-handling/project-conf.h b/tests/13-ieee802154/code-panid-handling/project-conf.h index 5c17b28a2..89b2c289e 100644 --- a/tests/13-ieee802154/code-panid-handling/project-conf.h +++ b/tests/13-ieee802154/code-panid-handling/project-conf.h @@ -29,8 +29,8 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _PROJECT_CONF_H_ -#define _PROJECT_CONF_H_ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ #define UNIT_TEST_PRINT_FUNCTION test_print_report @@ -38,4 +38,4 @@ #include "project-tsch-conf.h" #endif /* MAC_CONF_WITH_TSCH */ -#endif /* !_PROJECT_CONF_H_ */ +#endif /* !PROJECT_CONF_H_ */ From 8806fd2aca14654878b47d0cbc5d89d747b79372 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 21 Apr 2018 13:28:27 -0700 Subject: [PATCH 077/129] Discontinue multicast example on platform sky --- examples/multicast/Makefile | 2 ++ tests/01-compile-base/Makefile | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/multicast/Makefile b/examples/multicast/Makefile index 6037c8172..86c16e481 100644 --- a/examples/multicast/Makefile +++ b/examples/multicast/Makefile @@ -3,6 +3,8 @@ all: $(CONTIKI_PROJECT) # nrf52dk only supports slave mode, i.e., with no routing PLATFORMS_EXCLUDE = nrf52dk +# does not fit sky motes +PLATFORMS_EXCLUDE += sky CONTIKI = ../.. diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index 5dfb3f149..7184d69ac 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -7,7 +7,6 @@ hello-world/native:MAKE_NET=MAKE_NET_NULLNET \ hello-world/native:MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC \ hello-world/sky \ storage/eeprom-test/native \ -multicast/sky \ libs/logging/native \ libs/energest/native \ libs/energest/sky \ From d8a08e076bd11794b4b04acd26c11cafd08475df Mon Sep 17 00:00:00 2001 From: YK Date: Mon, 23 Apr 2018 11:14:57 +0800 Subject: [PATCH 078/129] Add ibm-watson-iot-platform-tls-optional.png to /img for README Add ibm-watson-iot-platform-tls-optional.png which shows how to set TLS optional on IBM Watson IoT Platform. --- .../ibm-watson-iot-platform-tls-optional.png | Bin 0 -> 86462 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/ibm-watson-iot-platform-tls-optional.png diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/img/ibm-watson-iot-platform-tls-optional.png b/examples/platform-specific/cc26xx/cc26xx-web-demo/img/ibm-watson-iot-platform-tls-optional.png new file mode 100644 index 0000000000000000000000000000000000000000..93c98624fddeefc38f66885bb184589c6a6c31e2 GIT binary patch literal 86462 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

^W%BQh})en4Y ztzBPLz!gJAe_zObD!HMrcYMG*OZq#tO7TJNNa17|2nHnak*k&5&U`HXQ2QF&GLviL zma@PDI;1;*AwsT$T&-%6U%OFeuMKv+JQhm&oh(LRo%4ZAW2FrK;G?VW-I4+zVmZq0 zo63*t-uqvFXT;_@)!t6HMOAtLh9-YJ`KP4HvB%R*cBO@1B(gqTWs?UdM1T;)w43wd zP$Ux@Ml7%7pQY8E=EPomh~P=9jXWl?;>^U3`MWGon}8YnlSAJv%)R_W-< zO)KS}-p*!o?f6!k@10}h9FHBwDs{;(h&y@HAFWQ&&t(p}eDAMKgkj_mXEL=P=s$%a zwtliMM6r+igsXg}#hZ0R6w)(cb*Qm~F_31mK9+^E$b!nvb1rm@`jlUPU*NfJ987J2 z?Je<+xl`6X2$fK8fa*D%WR#XKzfl}q>dj6hg~VL=hrD?NbUbR-oOr6r`!_1kZgxAy ztjUV#9mx`l6GwEPlK3@(1CA-}@;G3)Kt-4J!B$psDn0ztJI>S9pcyklPkTDl1Bd7) zPU6Hy-pO`IF#ZYn*pN*m`bx%y5ed-o~c{t@Q9e@ zJz#hqY?nHFjXd1k?DhlW^GmFyTk}N?9`g3QAflCAu?KVGSA2!aOPl_p3_)GX6b7NLf*B@Y0_7@{sN3v0Dw76KG3x8b15$N@Axn zHj~;!2FULA3yHql$E3q_{RdOx7%ld_;KCZzC5-_48yh*4LOjxDjc8{Vi>blcff^?R zd_fQf=nb@d`38CDe^$dK@Fw8AM^$pBy}r4DAq(Tz7{hR$xvhRiK}>Ja7cV{be10An zh0SQRGc<9yT$knkw&5W-y)^a+E|k?8sL&yj&cAgc$Z^9e^nVv%IF66_8i%_UElZq>ef376*;K$P@F^HeA3+-5dEZbx7!3;YFFSa~!4yLOYKE1AO8GB9x1hbw2QeQ=68zUq%KZ zsmEOCuvC7Z)q0DWqU+dB=QQY>M5?F{nEcJ8Z?06)kQc6@wxO2CT3o$3&4wS9Eis%d zZ%P%(CaQCBU!F~NbENEm%O24GijIxGE$SPFIl3Ws!h+0ybV!8wmR20VxT;7bQ;c!| zg>f)PsT#Mbs9#36@Cwgcza=eXu{z8J2VWIL{7$S&2Gn--#+{SC-z^g1Rc{+jMHhsX zwev(8(5|3Lrf`8R*6d_4fgLjOtO?Ro>Wh*c2W`cz%^|jFHO272vKqZ?LQ8`U*TJTi zrzy9Mnfi8x4Nm$FCw^BZfBf?JU-;>2r!@j~Zc+n(f(!n-#g@?rdg}jNL=G1;QmIOJ zL#RSDIOT&A&YNF4G(b9Y_)4TYswyBo8kV-iVt%3)rmE z%ZI6LouR+dpV>Q${>^g50ZYA0>Nun8nO;6^s$Z#oh9w`1&yuDhJb+98ZHn?w3_^&- zr(3jY6I3ryyh035ldEnpO|qi0b6e)PcbKNTKAS5f+ONIQIQ~**0JVUuMCR%8tVFH^ zS4!NNRsnPvP=^08<9g3GsW`RO%zla1VVv}?l+FIe2_ch;k}8n_h?ZqrMC-&<&kByG zU4dTptkWYU{ZQnk(@zw$3riUS{QcA`f`0QG40R2)*~0Puu0o zIVBg%eB(OQ5V8Bo+I+;5>letVr_vJmb=uXg$qk9XlGdp}X6C_VLW7CX8sllfH>T^z zu5ap~Yq)SThho^K>vH<_HkQOv8?3M6Z5DoCTWGi#*ybvID%zduc+9Q>`D%XJ|J{2Z z_-yv&wOx#Jho6kuIrmnB|0+`Lek!TSWyDA8-ZUmA2j$kpSpAA7gVW>Wf_vJ&#g~YX zlgMVphqaN)9Jr3)(rl`EoDkKt<83sys!AH0z-&T1fnV#rR1U0+EIM27qSB%Nsfr?M z>G<8tG@OLz%u254V#hb;iZQjn%B_ecddI?Y5xIQI@uc<@m>&DBb0qPZ_|_w%)qlv@ zb?oVpBU1#dF+=~&wd$AYiKYx;8jn9@i7%kgG&eJcx6#$??Xsf0%0R2r+HJmC8EJ+c zFBgkosa%bKI!As;?*NW z`XRC47xdc}b82!UdSb=?(RrknbSkrMjI6iOn>Q|=76qplJLMTcXcaHE$+=H}M|vI@ z)Cwy2j@^5^YOI1QnxU!h;?cxY=Zet_GU)$>3)md--%V``*G&G(U@vzisS7&}G82{p{Blcuwbo*DU)#Fr{e9G%9 zqB!wJMOc9va{yWcO#ojnolkVI(-#_D3V zW%wv3IC2dF{g6vkqfwQ;0{Gz$DaO=3?zehOMU0q=6&N1{Z(Ltu^nkUf&GY-P2!0w5 z2FPbzzpqE(vb=7U%g2mnTjYhnCUkHbo8{XHrmMF-^sK+{S6RaINQVx3(W88>Ol?*| zJJ@Pr8*{~RG!IzCRW`ecf>~>(p2e84(O&A+I6lGUy`<37nIaeBAg&H(=AZDPI`zL2 ze7{0dVwCf7eX2_@S^fqUzaI(SiC5P-ICB}@Yw4FYnXd8=Tx_`!d|{^Q?5^`_5tBD4 z=72~!l^MvGHB$+xca&Tz_CGGEUYq}^@;oByDnUzAV@*ccbM16*k{C2u@{98xLXL0= zvU6>oM3jKZ_Kzswcoy>YsU_E6RFKJ0Ky1+ZM#M?L?D(9Jd3=y%F>OjK)e(-wnk0yi zwxc!mX@X}{8NWsE_gqYG*<@oWmH+GQC!pwIN=l}y?-S+iF4gi`oLG^@9yQI|`)7 z^Z@1@Gj~;Ub-E9s8V^vFQc&AE-Tt=CO13wMWwilnhl;3nJ1uIR#tDa&G?p*k!9Q<& zZXe=NcvbACoEwVW@0fI+N{$v7;a})kerNDws+)U=$n*DNo!o%r@LSlyaqPl&P8lm! z%?a47qIB{0L0^uDpGS=F#i6-OSd0?(*N*_2k(!{h#DWVM7$vQn6Qj1B2#;TN-|=|` z2!*rP=W1!IK9meh@S>bW+gh_)Y>fihj~Y5JTz^>zV+f+LIZpb+Jz$MDcB?J#wV_zd z7bM5l>rxk(3E_1FMS3QeE=#&!0}nI=;00Y+KxrNDb3>}Vnc*h2&!KK3nya`}=pf+= zcZ`t+7s{g)mt)uG>`D#TjD$N9ijB>u^@p#~^FUNV+cfcRLv`)w#y^aJD(xVEdriK_ zDyJo08-7FAI|3FzD7CmhAjB#ozc#Ats(HlPVLWsA@Ecx;TL*H!QLjA^Z4Qs@@LNae zvsU9VFBSp^k=WGGO`4CreISbZIpild~}C+p{6P?Xx4)NVpc6Toq-Fw*@d^ z%E1qN#?N1J`!Wh}DHz)#l5V0J5|Vn~cWik~6qB+Rns>cFnYwT%yUTZtN{AvQaxJhW zrOk>Mb2}{Awr6yuKGe865kr)xvAiC_?K{| z=ud-*o^_``u+@{UH;nOClyexUsYBZ=IwljORnP{@&x8yyvU;Rc`hGF> zoofj;ks06M#azO)zbX|#RoB_XiM|PvMGz+(#3t&J8ub2yWk+M6W zep3E^sl-kTegfW6)%aQDJwbUN<2+p)n)Y6Mo~2-ULx|)vWfb!W;%DqQQF?Uti)9&Yh~@Welj z+-^T!Z{}KiQOrVQqs>o9tk*z9a+6!Eh~$&(N@xC@@dM?ci=@xi__M!ncB*~C5cBCw zo08c?JY&xO>Qa>m!L4;@3FGz9?e-9lRR666AmCE_9^#))Rpg@GG8N;-LCGVJ&D(Hl;0{gb zX1!GNJz9Fq)@JS79J5a0kpoh|CF4}@Y9iW#9Y=HQiTJ=Op$W~}CA+2ggnIlfB-d($ zI%Pg*t4p2lO;nf1tp`Z4r@`(9=PW$bHD}vYOubhAwOWlOZ?eR@C){lXsoV+Cn3t23 zGFD3cs=ZvbeW*FxB8!~ z23B|}m0=Ech;RY$oqaG?(5I-g1d8)70h-<~IhyGLaX@O=++qX0^v@s|`p;`dOQ93# z*)gSs?u+Si{8>$!Z=!Zm8!G3pa>t58hrv4m&RE^UL!)QieL+z}>mJvM>J;6@=%*1~cINlA@lFD0D-1D8D~*0&a;CzX6^# zfs(>xcgY~njVq;rjIstl!n~7nCVVn`DBCWAE4vFCVaa}YEc6CrOw}P(@r1OK*|W@| zP$Js{{}MS&URxy=mi@rZETP?vo&vFNe+ogJ=<95nrTqENa!OXX)g3Z3m zO~RQmj2YE#4Dnx7#Tk4Q6Igk$&BCdbs-}e`nm*yoVb?d$vjbISn~MXYX91t;ZYm2Z zpl>0sF2<5tE^b**mCl!Lzp6v)sBZZDxJG$Hz7)KC9&rUOmkAtVewslU>f8Aos%96S zR9MC3{2=+~*_pTN0SEA!f#Qqj=5*Pmn*0QOt2Pp-3we6usswMMzuoM(Jm;O8tRLUj zZQXb0k9m2!X}`h~#=#e-Y>C`Zzbh3S4%sA`}0 zvOf;iQQ)&ChY36A=n);DI6rXPn(fjk%j~sR_r5?u>rpzKIgmiDVyV5(H6XZz26>d# zS4+)$F&7v&!!iHkN5?mxON7z%eF*8~4k5EQjRaVU=6!5^%Jsv&cL_8GH1}?zCR?O;q{Nx=`>}U}8*;{zuca&^qDdq0vcFFMOogn{%?RwH86w?CZOHu1#2_P< z!e z*quIo&S6(jZv(34Jk zxGFZOmgKnAH>YWACi}oQ+>3TTTN;DL3@#@_nyfYkVLW%{=(Ty@`KVDZvw5UPGbbSl z2*rk_e5xX?n96QZbj~y!d$8F$jvYIl%M>YI!+~)E3wUwTD3tr2M(X%xFaE!=4=nyf(TZgWsG&Sax7L^U6XRgk%2#RaNStAo}A%wi|{yrIClGp$ww?#7J zI&k$cr@`n zc(k-Z#g_bXjLUOLzgTIRqa51?w)`v96y9=JTxA_5H4MBB2q%KmB}U7!`n@Z7o5>-b zHG~}&c`HF?tIp=x}Vecg}; z(q`yfI79I;s5k{Fk0*J7M zI3J%E^h-Bl)@yNV(h-95jk;>uQ$$6L85F~z->ii^6?og0=`EwXfrj)@QvbvRp- zuRGZhB&m$`-c|WQ{V`Tbo4v+OCMc%dj>1NKRcNpg-hTF*;Us}^8M^B=>CYLg+#|AT zDV}bQGeI@J@Kc8M<>W-agvC>dBoCi`n6cA|Frau9nUsHrP-2E;vh2gZ0l(m6^Rvt9 zWQ&1U?)`DA@2-y>*@%(v#n^+=&ddble-|v&7O$ocq)cYdv&yapiCP>MRkXWvlI>R; zoBbe6eu^TxC=uL{mDPd@UMe(YnH3{^N8xkq=6HQR$Z4@2N~@(CFPPO+)H>B#0t*jl zZ3yxc9)8&zD1WfEq0!<TQHM?GP6|)N^J&^KXWjnZheW+!dCa((*Un*D*k+AMTRe z`K`E>CjH)%sQ0`b`{(|GGm_E$u}jtV7@F|qO62#K!{EK=$WR8BW&~~XpiRx-&wNcp zp4=k@R-0X&63WdsOOpg{Gid+Fyc{tgx__k?a^rTe4i)IP`u$0Z=Yml3v)TR|Ke^gE zpsbra$27p~^&rvP-+)?nERf$aLUn1bk6YD`tW5(JPiNvn+oTi>k!%!pq~3W_hRH@Y z;k$;Xqs)M(GLXdkSZir{{+ePwKcFZ%A*Oouz4GH&l}kz*eZv@VoePB9EWz5&5am0X z3*A)1gGnK$=3b0rN}UH`#FT5=P5-R{aQZmU@`PhhvBoE-MYw7kx~%s*Y07uc3OZZ- z%7%EAR|H7j)_PsUo<$mAn44TC-h`g$VNU~?aNo}?Mu@WkO9uE(8akC+s?qxefi02@ zA~IO=UWM#E=KL2Nem{!{kfI}%TE-CoulI(o1a*i}IhNuzr~aibR2Q3mZ2({mD^H6< zupML=F}0$6Yc&q{Y@;%vT+jkrz?RzHvMcn7jfm)WF$$5Ezcwv zumim&3Tu@`YU4J)-D*~lGV6C_E+y4lFtPxR(7H?1+z8;>j)@7Igr43b}t}Q$8zHH73#P^l%4EbWHoCb z+!@V0tfoSuj*GfE3=7N6>HN2PuckgXWx}w7GFz(B=y1!@R1q@)xjV&ps;`O3q5-bt z)Plzn`mXZ;w0%wYbRgV9(Mw5qT94lf;q-Sg|p_b;$ijZ@`Vqu-FbE5WZ z-D9j^wq7M84!4${%n}ItQz@tO{)fwr@FpXe5}P42C~cbstY2zpPC%7nbwh6U(kUe? zh;uc{wRdx@_D$NsQ5C|kur!b_!t44Lv9C02t~Pg18>kvU>X%FR=~$s=X#3_-o4V5q z_aU(<%)0&f;}LqaUUC!Nv?k#6fFBx!7;qI`YARSHM_H{aTBH1d0=@-biLv}x!E9`W570QzRs4$Sy4NYBEx*T(%mQ#plp#JR^RPv9-ni=8ZP z^9w!Z2Y)2&juk?1Kas^T^EZN1Xi^1Vs-r5NkH*=0n=Bd4c}ERDA9xUOFQ@CwHGDnv zG?|@RZJY8<0(w^xRM*J%swKJfc%G4Bglx1?gjt0)5Aa?HxX+Wh@jF~>}kA-;wob|)E$)KYmjeP@i4R6cLNiKV)aUj(5dp#q*bt} zv)rtV?7I8@>Zyxn)Ysy14oZi$7N3o%{zqXfv;yZD>M_IBXrZl8s5NVTDtY@S=@w@( zMZlKzSxFVC6vEsF^cdK6DzamyAO6zYa{m|n3|VJ-$O3G=qL21BL!?x|51A?0?5!tZ zQ`LV$=;Tacu4e3z@~-qSn=dJ7I=-L%7(a3~zp~m{_1BvZYKLpxl*@puPYC`BtJJYC zk+Iyo-I3Y~oJC;kWT2|2!34rcb8AE&i8Vt%gSV0+n7k?q;K>&Eb_&yAZg!P^oRl?u zr+i0E$8UjsJ-0G%xHx!dlX~hBJp2ATlK!0Et|^}18J2g4HRV`S`Y)Jq~@-2=wzt9I&zlu2LeZWJU|WI+%T61^`Cq@8Fh zq-wClPa9l{cc%R4WZ8)P>1|w`tab=0A6Jn9F`j^jsh|8vUkUh@zW=rU88rn(=HrCh zF_@C7x!f?7VwVSX}6#U_4X3wbn~1ODAI@tEJbjd41O1-s9_Pd{6*nfcCC?~ zh3#Z!+vx2yC}-Aa#SA>Y5jrZ4yL1h&2H=$2dJGIVDu7JffZ(AExVx(CSSrAJfTH-0 zQKUhs7Yz+VQb(viLLGH-z~Ayo6d=s{qtv67mdU+FkH?&wUO10R)oVqveF$7u_8h0t z`UNt;>LyIyVdMk~=>$Qn;d(Wkr@M@gq$FWIS~Y|lH;Q4VNoo~y_j ziFx4+M;tLoKZ{sj0K?)aBjm^NrnS-I&0w-$!?R^rsX1I){L#z$`F46vTyug??>{w9 zHEmfwqYF!ppAN1+7hrSY&nC}cm@D)PQiqV>y)$`7ZAZV09_Ei3T7v{z8utkU=f{Ga zoB`ch3Wt#AtM{=Fge>LYuQ!N3BDC7qJ(lfc-aA=IP7eQN`=?52{(`wgUZpY1lr5SYgsipT9aL?JLJEn}FCO@zNM$B7f!mB$ zMoJI<%7~PA3z)@JFR`T(B+E=ba6IBmjm42g$0v4BOQm6j$%$yMB@!QvfLhOS<8;rA z@=BfiK{#Ls?~HKGRth*Sk6}YL@*!IeK@){iWc2A!_+^{El`7Bzo{OS;d#?VBxwq9} zl4;;JwvVo!Xr&XSeJ&WchH*7$0Idq`@sL<-h;cYj*zQz?PAX1aN@7@Pjp^1Ck>7;M ziXsZ1Em2=HAI%VEgfw4-J?ap|k3O2HKN#B^q1kGSXzV>KB#X9^rM}SFoZqc>$YJB= z18MWdfm$V6nK$D=Y^6f}#?J(Y2ht4r>2usW|3nL9=J^Z>It{*M^ynKov}8kB38u$h z+5z=kjql5G>9?B>ac+|5O2*kAuH8Ga{D@wtSPJToQT{Diq?28LQ&}MiV{vDN;8tPu zd`aZc7r3AN7wuz2#owU^|bIP#=pK z-c)?Fm$Y+UU0!EM>dFvC)={^*MvS>O!6w}UgJ?!h`2#j*DE;G88;lsT&*mrZlFyZ* zTJi&SKH+Y*5u$qil8nQ;KBNgyy&}y|03g_fGE(Ii<5ra|a}8kZ>i&eZKw!5oR?mek z_PB!_rcUc1L!rIjvmu1`5<{*&Nt5J|zqn-PcGMnh%vOT%p;J23S4H?hCB3#P79zC) zFb@u_K#~y2R_$o=wMziLFH=*L>dU*ZUy8l%KQcyPc?*jC<~Zvdb|-fxpY@1I6gL|d zhF4`Opmv0;2BIo~!|$$`sdveGSY^CB@JfUF_Ga((mC?)Qg|mkJb1NZq8yp3Gv7jb= z)90oc7M4G31aG=%47-?QbV9>5ku|XkjKlP)Hzvpv*(|-bSCW!*0>Ig78epfNVLtVV zzPK)72W$#W6cR1z58u(OVG;clzUAACt3{yCRehY%=;m7p-~hbC;})^S^^QPTjuBqs zK`6=Smz~d|W_-T*H$pko!5^m$q>AF+u;-tzF=}6f3n6+^b$ofZsfC%<=~vy*E<<_w9clicX8?-)@B-QgoUged1(E}%iUp;@ z|Am+j;q}(Lu6T|;mwt713!3yYd;XN}NMf$DOra<~Ni0?ic<@wHRewiT~@4=st z@&qLru`ZkR#f`p1jJVL=OgU*RTw!LZqZVh;S+HWY%1Tx8 zm&M=CLv!wy)c3F~h>rC&P-H5`@Rl#HI(LK7>RY7oRnMRCxt&h1sOrll0b@JtH8a(9 z!LgiPxG&P|Tv)ceYv_|!e-xi=Bf@6c1L2EE zmNjaFN;L?~A(XxQ*8R!NUP@(ktIO|sIg_GKGqOmf!FI8F7XUc&A2ZtTt1+&g7GaJL>?&k=|&AH(cpq?`H)xE6I>fzVs(uGQcuh z!Zs->$pTQ4e&7-Xr80T%Gbwc%@f9VL%k|d`9e^*X2;cW#uj978jUYV;6c#J(T+!AA zU?`TwtgInYEtnP4rp4sXW}T^74*xP2YBzb-fUveW>o0*#zb9o5eQmoT+50E5>aG?E zg)nH;N26bS-fae5R76q!1^A?-_RG-=VvtthN_%Uot2;@ZSeslGknAQuI z3v5vDZb_bl-D~Pw`P;TU5zRLK$*YjYR*-s{2w{_i z?btlKST;&klr>nD@mM>Rf{)gV=6*i_Vh#I;UnvXX1I2=5RalY+Ne=poF9}^H@|eAf z`kuH&+OdjT^DfVm#MNK6IG)h(mhR?MyJ{7_gFHP1+se<%`IB$+1}MIwo-vHXp_rAZZg@iqbggt2tDUd;5b(7>elzo3I$1b8 zi5{!!XhdSWe|J)kow>LJ+MZGjnp0{E7fWvLTTE0$Mymo7UPqX}ZP*-cMC5e82$=YgmwG@{ z)L&+iaisGZetFQJ`FROhoOUgh0wd|>^n-XgLh*ZK#hF3=Ip z!GX!-vPK^eb0Kj`%(%+OZmSHRLxh|djuJx;gbeNl);Ks3K0UlfhPkEV(HTq_q4~-E z?H)PIh;6))djQ@lvQ_J;-3xW%HiR{1@t+StZ0@XnlGdsD6+uK%-eIat!K#)!2g+4o zs5uFQY6jCyLW&+d*!cN#)MA!H6Ou`Uz|rDGh=;1VjX9H2#6UAGM)doQO6-wZa>RJ= z;iqUETy2jt8<4h(WsN>#Z=$8OIB}qXRh`s44wB?}8emy4;xog}b(YE|C$&0U{F{Y! zRC()&AZ~gqqEsiN)WfN&W7~@!xZIh*|pNZ1SBoINU8JX#t~mGAq-z?TKxN zt)V?Re7svGn|;B+Uc+^P2jUJdaRy6 zwO2ruz$5z^%4zg&ln)q^x9rBr9YyyB7)>=&Trk}*@VM%#n(L|YrKrTE>fE$3X|6(A zCvvpni~Yp~@ACR1KO1rl7q_R{w+<=YHfOWKq9Q#sC2-$5JHj?cg=NQHqJ>Eo&sNdz zt#t1(=SP`|GSi=R3`08!=@gt}H(uu@7d75Ypw-!~*9HQjcJWNJI zE%9lqW6RY5a3lib&S?Vs@g7>&$h+EJp59ha)uTDZZFB9K7L&72*^S$J?_=G$F2|G{ zH90n+pK9305MHmBmL5f=&j1}EC5<<1eEvr@T-(z6@+VbEqS3SgrbVQEg};f=gt)m& zHB<>`t>q-dJjKN6bX_(uhGTQjesd~?b~eeWjhcmxsOtyRllC3EL0^77xo-WdLm;`< z6{GETq&Cn;RPNKU_&A`X-G31hRO&2{^<;^3YIBP1^*ZxK3YF2J$Dn+QI}|~!-^ulX zbiN!<2?8Ns8|$+#5jdcnDAtQm)b0J~`y@qQsPy?404)9e*4B9tE4Rgul2YW~^P1lM z=VX}Q{oBev7Uag+T@k)tz_uV02~_%tcNq1DmFjms$txY*Z|0OFi*~A75wJso?j&wbngCD#Rc~?iS-Q@6aU-RM)!2woU{(_QjrPqg1EHqraqZ01*Q1%opT<(+tN~OiMufX9pFtph zdl2W0N>#G8Bkr$DFJE?u>j`J4Eurs{aOK@U;YVRKeD688gOOEJ82^^}zL~yAFShwho~Ytt*8z3zP<8rq@|w@2wQrI?VO7CkFqb1a zq>oEKTzC4&_wp~SRXIZ&WOwj$(4 zM&7C1obJqa<*2w!Lrbky@3?Zo<^XwqxedK3)=u;`dbi&2JDSH`thrQ;2ctsMQ4Fun z2A^M}n6Sgvr)R%iS=(z+tZ7ZXG|53Z2d!T_M zVz_l&xFlj4hZtj7>i;Z>|DQ+!?jnEh41})St?A36{%M8&SCoTe1}U-Fp51D#GW|dQ z&HqVq|9@Toueyj3U`(g1sj%{Yu_L+Ja10&@O8L|Oi*X;OJ^lOH|NQEfLQ(dAvjF~Yzx{vG%>O@_ zCbyT;6Fgsd%H_7A)Sw(=4yYzN!SUqH)^d)w$%{;T`FjAPZ7=M|Z(AOnY*#hnU-~1y z%1YjUuVj2;Vh{hX$Apj)X6vF4f^!>$ysG+Yb%kdAuSP#XdA*^z2 zyS;l^o7WBN3PIEgo0#xrjDI?2{}Eb2I)o5$fByX0uD3B7dRc~xmUo|z%&bL@Ak*fB z0ZCZw&&QIu$e zskB|fcsf<%;z%}*Y<;9wi>3A`vOCpi;jf<0j78HQe zP(uIns6C$G$~ta;O@eXK?3qc zX=$m!{L@+d!t=c5d+d?l*ANz9>`v&Zb_#1M^2f;3nU5}mGaA1eX7k>~I=R0{1~J}^ zRiKi)zg;|kxtD*1UPhPIbOjUe6yQK!QVou){NVUML--%w=nEWyoSHgt%}T`CnH35O zN={1)uIP!+H_QQrhnsu%>MCkHiHgYA6^@RM&NPW}X3L%dx>A(Y$|~e{jj)+qTCmO0 zXk}rL88Vt~K2%1sEQpQb%GC&Tm0;HXLY?QanpJ(h5{FEks>#AwDCg9=AHa?%cOedW zbuK$&OqD@HqV3Xaco-w}oM%d$0t31Pw#XW<**H?rt187vPeu!wl;bhrP#T({aYW!! zvlI59eaWTXAwY(vEEN$qKwV~y%tj*`(CEdqXGx7Yw@i^NGts-G&SCylfzGh93|!md z+dvvSk{weNj?q(1yuXsR#eBM9m61TtO$g^4uAsW!XoBjRAsA@JM=HeBqNmq@`}CD( zMN-qZ+GknoI>}gxhfrnR{l%!!2h?d&ZUK2m+KwjbS6gupdDqX%->SUd1Qae zqt(;9xI|3 z;Z=D9SZ4%rHmo<&Xmrd7S8QT{NOWH=+>?J*+9C**LKgG|Z?zOBRgJQ-vgM60YHEii z+SAQiBxLYMV)TU9wY*i`V}_WJ2!2=lU8AW1)#1j_TB2go;(Fn(w3 zTQHasNNQTemkVA<2ZJ@7v&6l5)%WyUaZ=<;0sKnEAmY3-`Dh#s0-@YC-jj^>u7Q4+*bkQ3~=3#fE zfL}TnIp}`hAY5GcJ`2k+$fMb!CnlBRCm!Ni%40PEJ0-6S)Ae603EtxixJnN=wjP$s zw)pJ^)pRiGAb-G^Vz|~)L)31Xg_sJ4-ogKyG``t-WP3o=j^eL^2_}p1JF7Lo#1_

-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%0D=VkAz5J-CT~FS`OOwW?JxP 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 Date: Sat, 28 Apr 2018 14:09:41 +0100 Subject: [PATCH 091/129] Enable the CC13x0/CC26x0 ROM bootloader by default --- arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h index 9c00a1823..8995aca8c 100644 --- a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h @@ -190,7 +190,7 @@ * @{ */ #ifndef ROM_BOOTLOADER_ENABLE -#define ROM_BOOTLOADER_ENABLE 0 +#define ROM_BOOTLOADER_ENABLE 1 #endif /** @} */ /*---------------------------------------------------------------------------*/ From 2ba54edaecd869c4743078b5aa2a79f19117626b Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 28 Apr 2018 01:36:14 +0100 Subject: [PATCH 092/129] Tidy-up renode for OS X and enable for all CC2538DK --- arch/platform/cc2538dk/Makefile.cc2538dk | 14 ++++++++++++++ examples/rpl-udp/Makefile | 15 --------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/arch/platform/cc2538dk/Makefile.cc2538dk b/arch/platform/cc2538dk/Makefile.cc2538dk index c452ccfaf..d80fd8d5f 100644 --- a/arch/platform/cc2538dk/Makefile.cc2538dk +++ b/arch/platform/cc2538dk/Makefile.cc2538dk @@ -37,3 +37,17 @@ else sort -g | head -1)) $(PYTHON) $(BSL) $(BSL_FLAGS) $(BSL_ADDRESS_ARG) $< endif + +ifeq ($(HOST_OS),Darwin) + RENODE = mono /Applications/Renode.app/Contents/MacOS/bin/Renode.exe +else + RENODE = renode +endif + +SCRIPT ?= $(notdir $(CURDIR)).resc + +.PHONY: renode + +renode: all + $(RENODE) $(SCRIPT) + diff --git a/examples/rpl-udp/Makefile b/examples/rpl-udp/Makefile index 26190e839..78e6d1653 100644 --- a/examples/rpl-udp/Makefile +++ b/examples/rpl-udp/Makefile @@ -1,20 +1,5 @@ CONTIKI_PROJECT = udp-client udp-server all: $(CONTIKI_PROJECT) -.PHONY: renode -renode: all -ifneq ($(TARGET),cc2538dk) - $(error Only the cc2538dk TARGET is supported for Renode demo scripts) -endif -ifndef SCRIPT - $(warning SCRIPT not defined! Using "rpl-udp.resc" as default) - renode rpl-udp.resc -else -ifeq ($(wildcard $(SCRIPT)),) - $(error SCRIPT "$(SCRIPT)" does not exist!) -endif - renode $(SCRIPT) -endif - CONTIKI=../.. include $(CONTIKI)/Makefile.include From a343f3b97e1a3603c0c66564a9a70511fe67b685 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 27 Apr 2018 21:55:44 +0100 Subject: [PATCH 093/129] Easily switch to IBM Watson platform mode --- examples/mqtt-client/mqtt-client.c | 73 ++++++++++++++++++++++------- examples/mqtt-client/project-conf.h | 34 +++++++++++++- 2 files changed, 89 insertions(+), 18 deletions(-) diff --git a/examples/mqtt-client/mqtt-client.c b/examples/mqtt-client/mqtt-client.c index 258660459..3183c878d 100644 --- a/examples/mqtt-client/mqtt-client.c +++ b/examples/mqtt-client/mqtt-client.c @@ -49,22 +49,61 @@ #define LOG_MODULE "mqtt-client" #define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ -/* - * IBM server: messaging.quickstart.internetofthings.ibmcloud.com - * (184.172.124.189) mapped in an NAT64 (prefix 64:ff9b::/96) IPv6 address - * Note: If not able to connect; lookup the IP address again as it may change. - * - * Alternatively, publish to a local MQTT broker (e.g. mosquitto) running on - * the node that hosts your border router - */ -#ifdef MQTT_CLIENT_CONF_BROKER_IP_ADDR -static const char *broker_ip = MQTT_CLIENT_CONF_BROKER_IP_ADDR; -#define DEFAULT_ORG_ID "contiki-ng" +/* Controls whether the example will work in IBM Watson IoT platform mode */ +#ifdef MQTT_CLIENT_CONF_WITH_IBM_WATSON +#define MQTT_CLIENT_WITH_IBM_WATSON MQTT_CLIENT_CONF_WITH_IBM_WATSON #else -static const char *broker_ip = "0064:ff9b:0000:0000:0000:0000:b8ac:7cbd"; -#define DEFAULT_ORG_ID "quickstart" +#define MQTT_CLIENT_WITH_IBM_WATSON 0 #endif /*---------------------------------------------------------------------------*/ +/* MQTT broker address. Ignored in Watson mode */ +#ifdef MQTT_CLIENT_CONF_BROKER_IP_ADDR +#define MQTT_CLIENT_BROKER_IP_ADDR MQTT_CLIENT_CONF_BROKER_IP_ADDR +#else +#define MQTT_CLIENT_BROKER_IP_ADDR "fd00::1" +#endif +/*---------------------------------------------------------------------------*/ +/* + * MQTT Org ID. + * + * If it equals "quickstart", the client will connect without authentication. + * In all other cases, the client will connect with authentication mode. + * + * In Watson mode, the username will be "use-token-auth". In non-Watson mode + * the username will be MQTT_CLIENT_USERNAME. + * + * In all cases, the password will be MQTT_CLIENT_AUTH_TOKEN. + */ +#ifdef MQTT_CLIENT_CONF_ORG_ID +#define MQTT_CLIENT_ORG_ID MQTT_CLIENT_CONF_ORG_ID +#else +#define MQTT_CLIENT_ORG_ID "quickstart" +#endif +/*---------------------------------------------------------------------------*/ +/* MQTT token */ +#ifdef MQTT_CLIENT_CONF_AUTH_TOKEN +#define MQTT_CLIENT_AUTH_TOKEN MQTT_CLIENT_CONF_AUTH_TOKEN +#else +#define MQTT_CLIENT_AUTH_TOKEN "AUTHTOKEN" +#endif +/*---------------------------------------------------------------------------*/ +#if MQTT_CLIENT_WITH_IBM_WATSON +/* With IBM Watson support */ +static const char *broker_ip = "0064:ff9b:0000:0000:0000:0000:b8ac:7cbd"; +#define MQTT_CLIENT_USERNAME "use-token-auth" + +#else /* MQTT_CLIENT_WITH_IBM_WATSON */ +/* Without IBM Watson support. To be used with other brokers, e.g. Mosquitto */ +static const char *broker_ip = MQTT_CLIENT_BROKER_IP_ADDR; + +#ifdef MQTT_CLIENT_CONF_USERNAME +#define MQTT_CLIENT_USERNAME MQTT_CLIENT_CONF_USERNAME +#else +#define MQTT_CLIENT_USERNAME "use-token-auth" +#endif + +#endif /* MQTT_CLIENT_WITH_IBM_WATSON */ +/*---------------------------------------------------------------------------*/ #ifdef MQTT_CLIENT_CONF_STATUS_LED #define MQTT_CLIENT_STATUS_LED MQTT_CLIENT_CONF_STATUS_LED #else @@ -133,7 +172,6 @@ static uint8_t state; /*---------------------------------------------------------------------------*/ /* Default configuration values */ #define DEFAULT_TYPE_ID "mqtt-client" -#define DEFAULT_AUTH_TOKEN "AUTHZ" #define DEFAULT_EVENT_TYPE_ID "status" #define DEFAULT_SUBSCRIBE_CMD_TYPE "+" #define DEFAULT_BROKER_PORT 1883 @@ -423,9 +461,10 @@ init_config() /* Populate configuration with default values */ memset(&conf, 0, sizeof(mqtt_client_config_t)); - memcpy(conf.org_id, DEFAULT_ORG_ID, strlen(DEFAULT_ORG_ID)); + memcpy(conf.org_id, MQTT_CLIENT_ORG_ID, strlen(MQTT_CLIENT_ORG_ID)); memcpy(conf.type_id, DEFAULT_TYPE_ID, strlen(DEFAULT_TYPE_ID)); - memcpy(conf.auth_token, DEFAULT_AUTH_TOKEN, strlen(DEFAULT_AUTH_TOKEN)); + memcpy(conf.auth_token, MQTT_CLIENT_AUTH_TOKEN, + strlen(MQTT_CLIENT_AUTH_TOKEN)); memcpy(conf.event_type_id, DEFAULT_EVENT_TYPE_ID, strlen(DEFAULT_EVENT_TYPE_ID)); memcpy(conf.broker_ip, broker_ip, strlen(broker_ip)); @@ -568,7 +607,7 @@ state_machine(void) state = STATE_ERROR; break; } else { - mqtt_set_username_password(&conn, "use-token-auth", + mqtt_set_username_password(&conn, MQTT_CLIENT_USERNAME, conf.auth_token); } } diff --git a/examples/mqtt-client/project-conf.h b/examples/mqtt-client/project-conf.h index 7b041ae38..66ba909ce 100644 --- a/examples/mqtt-client/project-conf.h +++ b/examples/mqtt-client/project-conf.h @@ -35,8 +35,40 @@ /* Enable TCP */ #define UIP_CONF_TCP 1 -/* If undefined, the demo will attempt to connect to IBM's quickstart */ +/* Change to 1 to use with the IBM Watson IoT platform */ +#define MQTT_CLIENT_CONF_WITH_IBM_WATSON 0 + +/* + * The IPv6 address of the MQTT broker to connect to. + * Ignored if MQTT_CLIENT_CONF_WITH_IBM_WATSON is 1 + */ #define MQTT_CLIENT_CONF_BROKER_IP_ADDR "fd00::1" + +/* + * The Organisation ID. + * + * When in Watson mode, the example will default to Org ID "quickstart" and + * will connect using non-authenticated mode. If you want to use registered + * devices, set your Org ID here and then make sure you set the correct token + * through MQTT_CLIENT_CONF_AUTH_TOKEN. + */ +#define MQTT_CLIENT_CONF_ORG_ID "quickstart" + +/* + * The MQTT username. + * + * Ignored in Watson mode: In this mode the username is always "use-token-auth" + */ +#define MQTT_CLIENT_CONF_USERNAME "mqtt-client-username" + +/* + * The MQTT auth token (password) used when connecting to the MQTT broker. + * + * Used with as well as without Watson. + * + * Transported in cleartext! + */ +#define MQTT_CLIENT_CONF_AUTH_TOKEN "AUTHTOKEN" /*---------------------------------------------------------------------------*/ #endif /* PROJECT_CONF_H_ */ /*---------------------------------------------------------------------------*/ From b012392ba4af2f6437a2692b61b2991cc0c95d0c Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 27 Apr 2018 22:23:22 +0100 Subject: [PATCH 094/129] Remove obsolete macros --- examples/mqtt-client/mqtt-client.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/mqtt-client/mqtt-client.c b/examples/mqtt-client/mqtt-client.c index 3183c878d..4e128ae37 100644 --- a/examples/mqtt-client/mqtt-client.c +++ b/examples/mqtt-client/mqtt-client.c @@ -161,11 +161,6 @@ static uint8_t state; #define CONFIG_CMD_TYPE_LEN 8 #define CONFIG_IP_ADDR_STR_LEN 64 /*---------------------------------------------------------------------------*/ -#define RSSI_MEASURE_INTERVAL_MAX 86400 /* secs: 1 day */ -#define RSSI_MEASURE_INTERVAL_MIN 5 /* secs */ -#define PUBLISH_INTERVAL_MAX 86400 /* secs: 1 day */ -#define PUBLISH_INTERVAL_MIN 5 /* secs */ -/*---------------------------------------------------------------------------*/ /* A timeout used when waiting to connect to a network */ #define NET_CONNECT_PERIODIC (CLOCK_SECOND >> 2) #define NO_NET_LED_DURATION (NET_CONNECT_PERIODIC >> 1) From 5fc521af56e373758ebf8123b7a580b7712e8248 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 27 Apr 2018 22:23:31 +0100 Subject: [PATCH 095/129] Update example README --- examples/mqtt-client/README.md | 38 +++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/examples/mqtt-client/README.md b/examples/mqtt-client/README.md index 44bba8877..8312ec024 100644 --- a/examples/mqtt-client/README.md +++ b/examples/mqtt-client/README.md @@ -13,25 +13,34 @@ The demo will give some visual feedback with a LED (configurable): This example is known to work with all platforms that support the new button API. +This example can operate in two modes: A default mode to be used with the +mosquitto MQTT broker and a second mode to be used with the IBM Watson IoT +platform. + +To enable Watson mode, define `MQTT_CLIENT_CONF_WITH_IBM_WATSON` as 1 in the +example's `project-conf.h`. + Publishing ---------- By default the example will attempt to publish readings to an MQTT broker -running on the IPv6 address specified as `MQTT_DEMO_BROKER_IP_ADDR` in +running on the IPv6 address specified as `MQTT_CLIENT_CONF_BROKER_IP_ADDR` in `project-conf.h`. This functionality was tested successfully with -[mosquitto](http://mosquitto.org/). +[mosquitto](http://mosquitto.org/). This define will be ignored in IBM Watson +mode. The publish messages include sensor readings but also some other information, such as device uptime in seconds and a message sequence number. The demo will publish to topic `iot-2/evt/status/fmt/json`. The device will connect using -client-id `d:contiki-ng:mqtt-client:`, where `` gets -constructed from the device's IEEE address. +client-id `d::mqtt-client:`, where `` gets +constructed from the device's IEEE address. `` can be controlled +through the `MQTT_CLIENT_CONF_ORG_ID` define. Subscribing ----------- You can also subscribe to topics and receive commands, but this will only work if you use "Org ID" != 'quickstart'. To achieve this, you will need to -change 'Org ID' (`DEFAULT_ORG_ID`). In this scenario, the device will subscribe -to: +change `MQTT_CLIENT_CONF_ORG_ID` in `project-conf.h`. In this scenario, the +device will subscribe to: `iot-2/cmd/+/fmt/json` @@ -53,13 +62,18 @@ messages, outgoing publish messages use proper json payload. IBM Quickstart Service ---------------------- It is also possible to publish to IBM's quickstart service. To do so, you need -to undefine `MQTT_DEMO_BROKER_IP_ADDR`. +to enable this mode by setting `MQTT_CLIENT_CONF_WITH_IBM_WATSON` to 1 in +`project-conf.h`. The device will then try to connect to IBM's quickstart over NAT64, so you will need a NAT64 gateway in your network to make this work. A guide on how to -setup NAT64 is out of scope here. +setup NAT64 is out of scope here, but you can find one in the +[Contiki-NG wiki](https://github.com/contiki-ng/contiki-ng/wiki/NAT64-for-Contiki%E2%80%90NG). -If you want to use IBM's cloud service with a registered device, change -'Org ID' (`DEFAULT_ORG_ID`) and provide the 'Auth Token' (`DEFAULT_AUTH_TOKEN`), -which acts as a 'password', but bear in mind that it gets transported in clear -text. +If you want to use IBM's cloud service with a registered device, you will need +to set `MQTT_CLIENT_CONF_ORG_ID` and then also to provide the 'Auth Token' +(`MQTT_CLIENT_CONF_AUTH_TOKEN`), which acts as a 'password'. You will also +need to configure your Organisation / Registered device on Watson such that +TLS is optional. + +Note: The token will be transported in cleartext. From 34ca2c06c199dd6b0b1441825827d46d09b07e21 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sat, 28 Apr 2018 13:02:11 -0700 Subject: [PATCH 096/129] TSCH: added file descriptions in .h files --- os/net/mac/tsch/tsch-adaptive-timesync.h | 2 ++ os/net/mac/tsch/tsch-asn.h | 8 ++------ os/net/mac/tsch/tsch-conf.h | 7 ++----- os/net/mac/tsch/tsch-const.h | 9 +++------ os/net/mac/tsch/tsch-log.h | 2 ++ os/net/mac/tsch/tsch-packet.h | 2 ++ os/net/mac/tsch/tsch-queue.h | 2 ++ os/net/mac/tsch/tsch-rpl.h | 2 ++ os/net/mac/tsch/tsch-schedule.h | 2 ++ os/net/mac/tsch/tsch-security.h | 2 ++ os/net/mac/tsch/tsch-slot-operation.h | 2 ++ os/net/mac/tsch/tsch-types.h | 7 ++----- os/net/mac/tsch/tsch.h | 2 ++ 13 files changed, 27 insertions(+), 22 deletions(-) diff --git a/os/net/mac/tsch/tsch-adaptive-timesync.h b/os/net/mac/tsch/tsch-adaptive-timesync.h index 574add542..c4ca20b7b 100644 --- a/os/net/mac/tsch/tsch-adaptive-timesync.h +++ b/os/net/mac/tsch/tsch-adaptive-timesync.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH adaptive time synchronization */ #ifndef __TSCH_ADAPTIVE_TIMESYNC_H__ diff --git a/os/net/mac/tsch/tsch-asn.h b/os/net/mac/tsch/tsch-asn.h index d58e7b27e..1db99b432 100644 --- a/os/net/mac/tsch/tsch-asn.h +++ b/os/net/mac/tsch/tsch-asn.h @@ -31,16 +31,12 @@ */ /** + * \addtogroup tsch + * @{ * \file * TSCH 5-Byte Absolute Slot Number (ASN) management * \author * Simon Duquennoy - * - */ - -/** - * \addtogroup tsch - * @{ */ #ifndef __TSCH_ASN_H__ diff --git a/os/net/mac/tsch/tsch-conf.h b/os/net/mac/tsch/tsch-conf.h index 8c94fbc9d..3ee47b9cb 100644 --- a/os/net/mac/tsch/tsch-conf.h +++ b/os/net/mac/tsch/tsch-conf.h @@ -31,17 +31,14 @@ */ /** +* \addtogroup tsch +* @{ * \file * TSCH configuration * \author * Simon Duquennoy */ -/** - * \addtogroup tsch - * @{ -*/ - #ifndef __TSCH_CONF_H__ #define __TSCH_CONF_H__ diff --git a/os/net/mac/tsch/tsch-const.h b/os/net/mac/tsch/tsch-const.h index 607bb3506..81ca7ffa8 100644 --- a/os/net/mac/tsch/tsch-const.h +++ b/os/net/mac/tsch/tsch-const.h @@ -31,17 +31,14 @@ */ /** +* \addtogroup tsch +* @{ * \file - * TSCH configuration + * TSCH constants * \author * Simon Duquennoy */ -/** - * \addtogroup tsch - * @{ -*/ - #ifndef __TSCH_CONST_H__ #define __TSCH_CONST_H__ diff --git a/os/net/mac/tsch/tsch-log.h b/os/net/mac/tsch/tsch-log.h index a16747cc0..468eff869 100644 --- a/os/net/mac/tsch/tsch-log.h +++ b/os/net/mac/tsch/tsch-log.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH per-slot logging */ #ifndef __TSCH_LOG_H__ diff --git a/os/net/mac/tsch/tsch-packet.h b/os/net/mac/tsch/tsch-packet.h index 1706ad97d..6b05d6653 100644 --- a/os/net/mac/tsch/tsch-packet.h +++ b/os/net/mac/tsch/tsch-packet.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH packet parsing and creation. EBs and EACKs. */ #ifndef __TSCH_PACKET_H__ diff --git a/os/net/mac/tsch/tsch-queue.h b/os/net/mac/tsch/tsch-queue.h index fcf460c97..b7edcf300 100644 --- a/os/net/mac/tsch/tsch-queue.h +++ b/os/net/mac/tsch/tsch-queue.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH queues */ #ifndef __TSCH_QUEUE_H__ diff --git a/os/net/mac/tsch/tsch-rpl.h b/os/net/mac/tsch/tsch-rpl.h index 0c71b0076..23a148db8 100644 --- a/os/net/mac/tsch/tsch-rpl.h +++ b/os/net/mac/tsch/tsch-rpl.h @@ -31,6 +31,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH-RPL interaction */ #ifndef __TSCH_RPL_H__ diff --git a/os/net/mac/tsch/tsch-schedule.h b/os/net/mac/tsch/tsch-schedule.h index 9a9a7330f..d98a744f3 100644 --- a/os/net/mac/tsch/tsch-schedule.h +++ b/os/net/mac/tsch/tsch-schedule.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH scheduling engine */ #ifndef __TSCH_SCHEDULE_H__ diff --git a/os/net/mac/tsch/tsch-security.h b/os/net/mac/tsch/tsch-security.h index 683bc6316..56c854414 100644 --- a/os/net/mac/tsch/tsch-security.h +++ b/os/net/mac/tsch/tsch-security.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH security */ #ifndef __TSCH_SECURITY_H__ diff --git a/os/net/mac/tsch/tsch-slot-operation.h b/os/net/mac/tsch/tsch-slot-operation.h index 63a9fbb51..1c71c5587 100644 --- a/os/net/mac/tsch/tsch-slot-operation.h +++ b/os/net/mac/tsch/tsch-slot-operation.h @@ -33,6 +33,8 @@ /** * \addtogroup tsch * @{ + * \file + * TSCH runtime operation within timeslots */ #ifndef __TSCH_SLOT_OPERATION_H__ diff --git a/os/net/mac/tsch/tsch-types.h b/os/net/mac/tsch/tsch-types.h index 6eb0f19a9..20f9911f6 100644 --- a/os/net/mac/tsch/tsch-types.h +++ b/os/net/mac/tsch/tsch-types.h @@ -31,17 +31,14 @@ */ /** +* \addtogroup tsch +* @{ * \file * TSCH types * \author * Simon Duquennoy */ -/** - * \addtogroup tsch - * @{ -*/ - #ifndef __TSCH_TYPES_H__ #define __TSCH_TYPES_H__ diff --git a/os/net/mac/tsch/tsch.h b/os/net/mac/tsch/tsch.h index 4a153f464..0f108bd93 100644 --- a/os/net/mac/tsch/tsch.h +++ b/os/net/mac/tsch/tsch.h @@ -37,6 +37,8 @@ The IEEE 802.15.4-2015 TimeSlotted Channel Hopping (TSCH) protocol. Provides scheduled communication on top of a globally-synchronized network. Performs frequency hopping for enhanced reliability. * @{ +* \file +* Main API declarations for TSCH. */ #ifndef __TSCH_H__ From 650a278e72cbb5a43856c9f2bfcc60d35929293e Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 30 Apr 2018 03:14:37 -0700 Subject: [PATCH 097/129] Dockerfile: add Renode --- tools/docker/Dockerfile | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index b03aa8b32..2ef5437a5 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -74,6 +74,20 @@ RUN sudo apt-get install -y npm \ && sudo npm install coap-cli -g \ && sudo ln -s /usr/bin/nodejs /usr/bin/node +# Install Mono and libcanberra-gtk:i386 (for Renode) +RUN sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF \ + && echo "deb http://download.mono-project.com/repo/ubuntu xenial main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list \ + && sudo apt-get update \ + && sudo apt-get install -y mono-complete gksu libgtk2.0-0 screen uml-utilities gtk-sharp2 libcanberra-gtk-module:i386 \ + && sudo apt-get clean + +# Download, build and install Renode +RUN git clone https://github.com/renode/renode.git \ + && cd ${HOME}/renode \ + && git checkout v1.3 \ + && ./build.sh +ENV PATH="${HOME}/renode:${PATH}" + # Optional: download Contiki-NG and pre-compile Cooja. # Else, use a Docker bind mount to share the repo with the host. # Docker run option: From 181cb57057819a8783ca85e451fd56a372a1ea38 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 30 Apr 2018 03:15:05 -0700 Subject: [PATCH 098/129] Dockerfile: minor fix --- tools/docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 2ef5437a5..be28bf682 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -98,8 +98,8 @@ RUN ant -q -f ${CONTIKI_NG}/tools/cooja/build.xml jar # Working directory WORKDIR ${CONTIKI_NG} -# Enable IPv6 -- must be done at runtime, not in Dockerfile -RUN echo "sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null" >> /home/user/.profile +# Enable IPv6 -- must be done at runtime, hence added to .profile +RUN echo "sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0 > /dev/null" >> ${HOME}/.profile # Start a bash CMD bash --login From 7f7da4367e9f498b0005e13a7d7ed3fe16fb18c9 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Thu, 3 May 2018 12:39:09 -0700 Subject: [PATCH 099/129] Make distclean: less verbose output --- Makefile.include | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile.include b/Makefile.include index dd24fcacb..3fdb2eb31 100644 --- a/Makefile.include +++ b/Makefile.include @@ -298,14 +298,15 @@ CONTIKI_NG_PROJECT_MAP = $(addsuffix -$(TARGET).map, $(basename $@)) .PHONY: clean distclean usage help targets boards savetarget savedefines viewconf clean: - -rm -f *.d *.e *.o $(CONTIKI_NG_TARGET_LIB) $(CLEAN) - -rm -rf $(OBJECTDIR) - -rm -f $(addsuffix -$(TARGET).map, $(CONTIKI_PROJECT)) - -rm -f $(addsuffix .$(TARGET), $(CONTIKI_PROJECT)) + -$(Q)rm -f *.d *.e *.o $(CONTIKI_NG_TARGET_LIB) $(CLEAN) + -$(Q)rm -rf $(OBJECTDIR) + -$(Q)rm -f $(addsuffix -$(TARGET).map, $(CONTIKI_PROJECT)) + -$(Q)rm -f $(addsuffix .$(TARGET), $(CONTIKI_PROJECT)) + @echo Target $(TARGET) cleaned distclean: @for TARG in `ls $(CONTIKI)/arch/platform $(TARGETDIRS)`; do \ - echo make $$TARG clean; \ + echo Running: make TARGET=$$TARG clean; \ make TARGET=$$TARG clean; \ done From d17566aaefa67e72becfb1af084dda8afae5fb1d Mon Sep 17 00:00:00 2001 From: Olav Frengstad Date: Thu, 3 May 2018 17:00:07 +0200 Subject: [PATCH 100/129] Allow custom frequency bands (+ some TI radio tweak options) * Add DOT_15_4G_FREQUENCY_BAND_CUSTOM for configuring non-standard frequency band * Add option to tweak some timer settings --- arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h | 8 +++ arch/cpu/cc26xx-cc13xx/rf-core/dot-15-4g.h | 57 ++++++++++++++++----- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h index 8995aca8c..df1ca0440 100644 --- a/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h +++ b/arch/cpu/cc26xx-cc13xx/cc13xx-cc26xx-conf.h @@ -78,9 +78,17 @@ #define IEEE802154_CONF_DEFAULT_CHANNEL 0 #endif /* IEEE802154_CONF_DEFAULT_CHANNEL */ +#ifndef CSMA_CONF_ACK_WAIT_TIME #define CSMA_CONF_ACK_WAIT_TIME (RTIMER_SECOND / 400) +#endif /* CSMA_CONF_ACK_WAIT_TIME */ + +#ifndef CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME #define CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME (RTIMER_SECOND / 1000) +#endif /* CSMA_CONF_AFTER_ACK_DETECTED_WAIT_TIME */ + +#ifndef CSMA_CONF_SEND_SOFT_ACK #define CSMA_CONF_SEND_SOFT_ACK 1 +#endif /* CSMA_CONF_SEND_SOFT_ACK */ #else /* CC13XX_CONF_PROP_MODE */ #ifndef NETSTACK_CONF_RADIO diff --git a/arch/cpu/cc26xx-cc13xx/rf-core/dot-15-4g.h b/arch/cpu/cc26xx-cc13xx/rf-core/dot-15-4g.h index 7282ac9ba..37c5d3e34 100644 --- a/arch/cpu/cc26xx-cc13xx/rf-core/dot-15-4g.h +++ b/arch/cpu/cc26xx-cc13xx/rf-core/dot-15-4g.h @@ -49,20 +49,21 @@ #include "driverlib/rf_mailbox.h" /*---------------------------------------------------------------------------*/ /* IEEE 802.15.4g frequency band identifiers (Table 68f) */ -#define DOT_15_4G_FREQUENCY_BAND_169 0 /* 169.400–169.475 (Europe) - 169 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_450 1 /* 450–470 (US FCC Part 22/90) - 450 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_470 2 /* 470–510 (China) - 470 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_780 3 /* 779–787 (China) - 780 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_863 4 /* 863–870 (Europe) - 863 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_896 5 /* 896–901 (US FCC Part 90) - 896 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_901 6 /* 901–902 (US FCC Part 24) - 901 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_915 7 /* 902–928 (US) - 915 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_917 8 /* 917–923.5 (Korea) - 917 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_920 9 /* 920–928 (Japan) - 920 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_928 10 /* 928–960 (US, non-contiguous) - 928 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_950 11 /* 950–958 (Japan) - 950 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_1427 12 /* 1427–1518 (US and Canada, non-contiguous) - 1427 MHz band */ -#define DOT_15_4G_FREQUENCY_BAND_2450 13 /* 2400–2483.5 2450 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_169 0 /* 169.400–169.475 (Europe) - 169 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_450 1 /* 450–470 (US FCC Part 22/90) - 450 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_470 2 /* 470–510 (China) - 470 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_780 3 /* 779–787 (China) - 780 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_863 4 /* 863–870 (Europe) - 863 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_896 5 /* 896–901 (US FCC Part 90) - 896 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_901 6 /* 901–902 (US FCC Part 24) - 901 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_915 7 /* 902–928 (US) - 915 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_917 8 /* 917–923.5 (Korea) - 917 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_920 9 /* 920–928 (Japan) - 920 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_928 10 /* 928–960 (US, non-contiguous) - 928 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_950 11 /* 950–958 (Japan) - 950 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_1427 12 /* 1427–1518 (US and Canada, non-contiguous) - 1427 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_2450 13 /* 2400–2483.5 2450 MHz band */ +#define DOT_15_4G_FREQUENCY_BAND_CUSTOM 14 /* For use with custom frequency band settings */ /*---------------------------------------------------------------------------*/ /* Default band selection to band 4 - 863MHz */ #ifdef DOT_15_4G_CONF_FREQUENCY_BAND_ID @@ -77,6 +78,18 @@ * bands we only support operating mode #1 (Table 134). * * DOT_15_4G_CHAN0_FREQUENCY is specified here in KHz + * + * Custom bands and configuration can be used with DOT_15_4G_FREQUENCY_BAND_CUSTOM. + * + * Example of custom setup for the 868Mhz sub-band in Europe with 11 channels, + * center frequency at 868.050MHz and channel spacing at 100KHz. + * These should be put in project-config.h or similar. + * + * #define DOT_15_4G_FREQUENCY_BAND_ID DOT_15_4G_FREQUENCY_BAND_CUSTOM + * #define DOT_15_4G_CHAN0_FREQUENCY 868050 + * #define DOT_15_4G_CHANNEL_SPACING 100 + * #define DOT_15_4G_CHANNEL_MAX 11 + * #define PROP_MODE_CONF_LO_DIVIDER 0x05 */ #if DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_470 #define DOT_15_4G_CHANNEL_MAX 198 @@ -116,6 +129,22 @@ #define DOT_15_4G_CHAN0_FREQUENCY 951000 #define PROP_MODE_CONF_LO_DIVIDER 0x05 +#elif DOT_15_4G_FREQUENCY_BAND_ID==DOT_15_4G_FREQUENCY_BAND_CUSTOM +#ifndef DOT_15_4G_CHANNEL_MAX +#error DOT_15_4G_CHANNEL_MAX must be manually set when using custom frequency band +#endif + +#ifndef DOT_15_4G_CHANNEL_SPACING +#error DOT_15_4G_CHANNEL_SPACING must be manually set when using custom frequency band +#endif + +#ifndef DOT_15_4G_CHAN0_FREQUENCY +#error DOT_15_4G_CHAN0_FREQUENCY must be manually set when using custom frequency band +#endif + +#ifndef PROP_MODE_CONF_LO_DIVIDER +#error PROP_MODE_CONF_LO_DIVIDER must be manually set when using custom frequency band +#endif #else #error The selected frequency band is not supported #endif From dd335bb3183e6c8f2679332b06929d5ff05afae1 Mon Sep 17 00:00:00 2001 From: Olav Frengstad Date: Fri, 13 Apr 2018 11:16:27 +0200 Subject: [PATCH 101/129] Treat linker warnings as errors When using relative path (ie `./contiki-ng`) some Makefiles, like cortex m3, fails to filter out ldscripts resulting in a broken build. --- Makefile.include | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.include b/Makefile.include index dd24fcacb..e8dcbe672 100644 --- a/Makefile.include +++ b/Makefile.include @@ -49,6 +49,8 @@ CFLAGS += -DCONTIKI_BOARD_$(TARGET_BOARD_UPPERCASE)=1 CFLAGS += -DCONTIKI_BOARD_STRING=\"$(BOARD)\" endif +LDFLAGS = -Wl,--fatal-warnings + MODULES += os os/sys os/dev os/lib os/services # Automatically include project-conf.h if found From c176103aae595b0a1032baebaf4a6e2f65e87302 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 09:09:15 +0200 Subject: [PATCH 102/129] shell: check if a preferred parent exists before showing status --- os/services/shell/shell-commands.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/os/services/shell/shell-commands.c b/os/services/shell/shell-commands.c index 7920fb086..c1ba2921f 100644 --- a/os/services/shell/shell-commands.c +++ b/os/services/shell/shell-commands.c @@ -173,8 +173,12 @@ PT_THREAD(cmd_rpl_status(struct pt *pt, shell_output_func output, char *args)) SHELL_OUTPUT(output, "-- State: %s\n", rpl_state_to_str(curr_instance.dag.state)); SHELL_OUTPUT(output, "-- Preferred parent: "); - shell_output_6addr(output, rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent)); - SHELL_OUTPUT(output, " (last DTSN: %u)\n", curr_instance.dag.preferred_parent->dtsn); + if(curr_instance.dag.preferred_parent) { + shell_output_6addr(output, rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent)); + SHELL_OUTPUT(output, " (last DTSN: %u)\n", curr_instance.dag.preferred_parent->dtsn); + } else { + SHELL_OUTPUT(output, "None\n"); + } SHELL_OUTPUT(output, "-- Rank: %u\n", curr_instance.dag.rank); SHELL_OUTPUT(output, "-- Lowest rank: %u (%u)\n", curr_instance.dag.lowest_rank, curr_instance.max_rankinc); SHELL_OUTPUT(output, "-- DTSN out: %u\n", curr_instance.dtsn_out); From 846ab211b676bbb835378663522c6327c4323413 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 4 May 2018 00:43:31 -0700 Subject: [PATCH 103/129] Nullrouting: lowercase string description --- os/net/routing/nullrouting/nullrouting.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/routing/nullrouting/nullrouting.c b/os/net/routing/nullrouting/nullrouting.c index 14c328b0c..1b23d453a 100644 --- a/os/net/routing/nullrouting/nullrouting.c +++ b/os/net/routing/nullrouting/nullrouting.c @@ -149,7 +149,7 @@ drop_route(uip_ds6_route_t *route) } /*---------------------------------------------------------------------------*/ const struct routing_driver nullrouting_driver = { - "Null Routing", + "nullrouting", init, root_set_prefix, root_start, From 641a0d5e45b5c6258cf783ab8176076d265c2511 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 09:49:27 +0200 Subject: [PATCH 104/129] shell: the rpl-refresh-routes API is currently only provided by rpl-lite --- os/services/shell/shell-commands.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/os/services/shell/shell-commands.c b/os/services/shell/shell-commands.c index c1ba2921f..3dbce09f2 100644 --- a/os/services/shell/shell-commands.c +++ b/os/services/shell/shell-commands.c @@ -417,6 +417,7 @@ PT_THREAD(cmd_rpl_local_repair(struct pt *pt, shell_output_func output, char *ar PT_END(pt); } /*---------------------------------------------------------------------------*/ +#if ROUTING_CONF_RPL_LITE static PT_THREAD(cmd_rpl_refresh_routes(struct pt *pt, shell_output_func output, char *args)) { @@ -427,6 +428,7 @@ PT_THREAD(cmd_rpl_refresh_routes(struct pt *pt, shell_output_func output, char * PT_END(pt); } +#endif /* ROUTING_CONF_RPL_LITE */ #endif /* UIP_CONF_IPV6_RPL */ /*---------------------------------------------------------------------------*/ static @@ -736,7 +738,9 @@ struct shell_command_t shell_commands[] = { #if UIP_CONF_IPV6_RPL { "rpl-set-root", cmd_rpl_set_root, "'> rpl-set-root 0/1 [prefix]': Sets node as root (1) or not (0). A /64 prefix can be optionally specified." }, { "rpl-local-repair", cmd_rpl_local_repair, "'> rpl-local-repair': Triggers a RPL local repair" }, +#if ROUTING_CONF_RPL_LITE { "rpl-refresh-routes", cmd_rpl_refresh_routes, "'> rpl-refresh-routes': Refreshes all routes through a DTSN increment" }, +#endif /* ROUTING_CONF_RPL_LITE */ { "rpl-global-repair", cmd_rpl_global_repair, "'> rpl-global-repair': Triggers a RPL global repair" }, #endif /* UIP_CONF_IPV6_RPL */ #if ROUTING_CONF_RPL_LITE From 57ad48ca40dcb9a91283977080a6cb6887686e3a Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 10:43:23 +0200 Subject: [PATCH 105/129] Added compile regression test for native rpl-border-router with RPL Classic --- tests/01-compile-base/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/01-compile-base/Makefile b/tests/01-compile-base/Makefile index 5dfb3f149..67346c086 100644 --- a/tests/01-compile-base/Makefile +++ b/tests/01-compile-base/Makefile @@ -18,6 +18,7 @@ lwm2m-ipso-objects/native \ lwm2m-ipso-objects/native:MAKE_WITH_DTLS=1 \ rpl-udp/sky \ rpl-border-router/native \ +rpl-border-router/native:MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC \ rpl-border-router/sky \ slip-radio/sky \ libs/ipv6-hooks/sky \ From 5c4fad921ebcdd4eaf131eaa3f1bf9776372ed01 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 10:58:58 +0200 Subject: [PATCH 106/129] coap: shorter log module names for aligned log output --- os/net/app-layer/coap/coap-block1.c | 2 +- os/net/app-layer/coap/coap-blocking-api.c | 2 +- os/net/app-layer/coap/coap-callback-api.c | 2 +- os/net/app-layer/coap/coap-observe-client.c | 2 +- os/net/app-layer/coap/coap-observe.c | 2 +- os/net/app-layer/coap/coap-res-well-known-core.c | 2 +- os/net/app-layer/coap/coap-separate.c | 2 +- os/net/app-layer/coap/coap-timer-default.c | 2 +- os/net/app-layer/coap/coap-transactions.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/os/net/app-layer/coap/coap-block1.c b/os/net/app-layer/coap/coap-block1.c index e08a321d1..600c09b27 100644 --- a/os/net/app-layer/coap/coap-block1.c +++ b/os/net/app-layer/coap/coap-block1.c @@ -49,7 +49,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-block1" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP /*---------------------------------------------------------------------------*/ diff --git a/os/net/app-layer/coap/coap-blocking-api.c b/os/net/app-layer/coap/coap-blocking-api.c index 0d2c5dc58..1be7cbe7c 100644 --- a/os/net/app-layer/coap/coap-blocking-api.c +++ b/os/net/app-layer/coap/coap-blocking-api.c @@ -51,7 +51,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-blocking-api" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP /*---------------------------------------------------------------------------*/ diff --git a/os/net/app-layer/coap/coap-callback-api.c b/os/net/app-layer/coap/coap-callback-api.c index 652856233..b1b05597e 100644 --- a/os/net/app-layer/coap/coap-callback-api.c +++ b/os/net/app-layer/coap/coap-callback-api.c @@ -51,7 +51,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-callback-api" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP /* These should go into the state struct so that we can have multiple diff --git a/os/net/app-layer/coap/coap-observe-client.c b/os/net/app-layer/coap/coap-observe-client.c index af1e89f14..a27308494 100644 --- a/os/net/app-layer/coap/coap-observe-client.c +++ b/os/net/app-layer/coap/coap-observe-client.c @@ -55,7 +55,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-observe-client" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP MEMB(obs_subjects_memb, coap_observee_t, COAP_MAX_OBSERVEES); diff --git a/os/net/app-layer/coap/coap-observe.c b/os/net/app-layer/coap/coap-observe.c index 676c4d1b3..83f5edf4a 100644 --- a/os/net/app-layer/coap/coap-observe.c +++ b/os/net/app-layer/coap/coap-observe.c @@ -50,7 +50,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-observe" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP /*---------------------------------------------------------------------------*/ diff --git a/os/net/app-layer/coap/coap-res-well-known-core.c b/os/net/app-layer/coap/coap-res-well-known-core.c index 2893925c9..ebaae8fd4 100644 --- a/os/net/app-layer/coap/coap-res-well-known-core.c +++ b/os/net/app-layer/coap/coap-res-well-known-core.c @@ -47,7 +47,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-res-well-known-core" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP #define ADD_CHAR_IF_POSSIBLE(char) \ diff --git a/os/net/app-layer/coap/coap-separate.c b/os/net/app-layer/coap/coap-separate.c index 318a4e53d..7eb5e5675 100644 --- a/os/net/app-layer/coap/coap-separate.c +++ b/os/net/app-layer/coap/coap-separate.c @@ -49,7 +49,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-separate" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP /*---------------------------------------------------------------------------*/ diff --git a/os/net/app-layer/coap/coap-timer-default.c b/os/net/app-layer/coap/coap-timer-default.c index ad1b30d28..7da3dfb05 100644 --- a/os/net/app-layer/coap/coap-timer-default.c +++ b/os/net/app-layer/coap/coap-timer-default.c @@ -52,7 +52,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-timer-default" +#define LOG_MODULE "coap-timer" #define LOG_LEVEL LOG_LEVEL_NONE PROCESS(coap_timer_process, "coap timer process"); diff --git a/os/net/app-layer/coap/coap-transactions.c b/os/net/app-layer/coap/coap-transactions.c index 652737b94..7e34d22e4 100644 --- a/os/net/app-layer/coap/coap-transactions.c +++ b/os/net/app-layer/coap/coap-transactions.c @@ -50,7 +50,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "coap-transactions" +#define LOG_MODULE "coap" #define LOG_LEVEL LOG_LEVEL_COAP /*---------------------------------------------------------------------------*/ From 3c1273805021cf4485b24d5e4a9c00d543ece385 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 11:02:25 +0200 Subject: [PATCH 107/129] lwm2m: shorter log module names for aligned log output --- os/services/lwm2m/lwm2m-device.c | 2 +- os/services/lwm2m/lwm2m-engine.c | 2 +- os/services/lwm2m/lwm2m-firmware.c | 2 +- os/services/lwm2m/lwm2m-plain-text.c | 2 +- os/services/lwm2m/lwm2m-rd-client.c | 2 +- os/services/lwm2m/lwm2m-security.c | 2 +- os/services/lwm2m/lwm2m-server.c | 2 +- os/services/lwm2m/lwm2m-tlv-writer.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/os/services/lwm2m/lwm2m-device.c b/os/services/lwm2m/lwm2m-device.c index 9e91b37fd..4183c59ca 100644 --- a/os/services/lwm2m/lwm2m-device.c +++ b/os/services/lwm2m/lwm2m-device.c @@ -48,7 +48,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-device" +#define LOG_MODULE "lwm2m-dev" #define LOG_LEVEL LOG_LEVEL_LWM2M static const lwm2m_resource_id_t resources[] = diff --git a/os/services/lwm2m/lwm2m-engine.c b/os/services/lwm2m/lwm2m-engine.c index b96674215..1dca95a44 100644 --- a/os/services/lwm2m/lwm2m-engine.c +++ b/os/services/lwm2m/lwm2m-engine.c @@ -63,7 +63,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-engine" +#define LOG_MODULE "lwm2m-eng" #define LOG_LEVEL LOG_LEVEL_LWM2M #ifndef LWM2M_ENGINE_CLIENT_ENDPOINT_PREFIX diff --git a/os/services/lwm2m/lwm2m-firmware.c b/os/services/lwm2m/lwm2m-firmware.c index e89c3dab4..87815d684 100644 --- a/os/services/lwm2m/lwm2m-firmware.c +++ b/os/services/lwm2m/lwm2m-firmware.c @@ -44,7 +44,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-firmware" +#define LOG_MODULE "lwm2m-fw" #define LOG_LEVEL LOG_LEVEL_LWM2M #define UPDATE_PACKAGE 0 diff --git a/os/services/lwm2m/lwm2m-plain-text.c b/os/services/lwm2m/lwm2m-plain-text.c index bbd293aa0..3dc816ddc 100644 --- a/os/services/lwm2m/lwm2m-plain-text.c +++ b/os/services/lwm2m/lwm2m-plain-text.c @@ -49,7 +49,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-plain-text" +#define LOG_MODULE "lwm2m-text" #define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ diff --git a/os/services/lwm2m/lwm2m-rd-client.c b/os/services/lwm2m/lwm2m-rd-client.c index 0f904ee4d..03d21e33e 100644 --- a/os/services/lwm2m/lwm2m-rd-client.c +++ b/os/services/lwm2m/lwm2m-rd-client.c @@ -64,7 +64,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-rd-client" +#define LOG_MODULE "lwm2m-rd" #define LOG_LEVEL LOG_LEVEL_LWM2M #ifndef LWM2M_DEFAULT_CLIENT_LIFETIME diff --git a/os/services/lwm2m/lwm2m-security.c b/os/services/lwm2m/lwm2m-security.c index 5fe0c31cb..e4275f280 100644 --- a/os/services/lwm2m/lwm2m-security.c +++ b/os/services/lwm2m/lwm2m-security.c @@ -54,7 +54,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-security" +#define LOG_MODULE "lwm2m-sec" #define LOG_LEVEL LOG_LEVEL_LWM2M #define MAX_COUNT LWM2M_SERVER_MAX_COUNT diff --git a/os/services/lwm2m/lwm2m-server.c b/os/services/lwm2m/lwm2m-server.c index 67b2c45ba..bf0398b4f 100644 --- a/os/services/lwm2m/lwm2m-server.c +++ b/os/services/lwm2m/lwm2m-server.c @@ -51,7 +51,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-server" +#define LOG_MODULE "lwm2m-srv" #define LOG_LEVEL LOG_LEVEL_LWM2M #define MAX_COUNT LWM2M_SERVER_MAX_COUNT diff --git a/os/services/lwm2m/lwm2m-tlv-writer.c b/os/services/lwm2m/lwm2m-tlv-writer.c index 6df16447e..41bdc2f6c 100644 --- a/os/services/lwm2m/lwm2m-tlv-writer.c +++ b/os/services/lwm2m/lwm2m-tlv-writer.c @@ -47,7 +47,7 @@ /* Log configuration */ #include "coap-log.h" -#define LOG_MODULE "lwm2m-tlv-writer" +#define LOG_MODULE "lwm2m-tlv" #define LOG_LEVEL LOG_LEVEL_NONE /*---------------------------------------------------------------------------*/ From f6330996f74548c91bafc6b188eb6c6f8a60dc27 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 11:11:17 +0200 Subject: [PATCH 108/129] dtls: shorter log module name for aligned log output --- os/net/app-layer/coap/tinydtls-support/dtls-support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/app-layer/coap/tinydtls-support/dtls-support.c b/os/net/app-layer/coap/tinydtls-support/dtls-support.c index ad960b718..4675c76d0 100644 --- a/os/net/app-layer/coap/tinydtls-support/dtls-support.c +++ b/os/net/app-layer/coap/tinydtls-support/dtls-support.c @@ -42,7 +42,7 @@ #include /* Log configuration */ -#define LOG_MODULE "dtls-support" +#define LOG_MODULE "dtls" #define LOG_LEVEL LOG_LEVEL_DTLS #include "dtls-log.h" #include "coap-log.h" From 15e51288ec0d6114c059b8efd81a39278a766dba Mon Sep 17 00:00:00 2001 From: Joakim Eriksson Date: Fri, 4 May 2018 18:01:18 +0200 Subject: [PATCH 109/129] fixed platforms to build for in Makefile --- examples/storage/antelope-shell/Makefile | 2 +- examples/storage/cfs-coffee/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/storage/antelope-shell/Makefile b/examples/storage/antelope-shell/Makefile index 3b3f7fd23..5eff3dcd3 100644 --- a/examples/storage/antelope-shell/Makefile +++ b/examples/storage/antelope-shell/Makefile @@ -3,7 +3,7 @@ CONTIKI = ../../.. MODULES += os/storage/antelope os/services/unit-test # does not fit on Sky -PLATFORMS_ONLY= cc2538 +PLATFORMS_ONLY= cc2538dk zoul CONTIKI_PROJECT = shell-db all: $(CONTIKI_PROJECT) diff --git a/examples/storage/cfs-coffee/Makefile b/examples/storage/cfs-coffee/Makefile index 10d6256fa..b6d22f5ac 100644 --- a/examples/storage/cfs-coffee/Makefile +++ b/examples/storage/cfs-coffee/Makefile @@ -1,6 +1,6 @@ CONTIKI = ../../.. -PLATFORMS_ONLY= cc2538 sky +PLATFORMS_ONLY= cc2538dk zoul sky MODULES += os/services/unit-test MODULES += os/storage/cfs From f5cee451d1d2df3e8deb2034b445c1196b2bfa77 Mon Sep 17 00:00:00 2001 From: Nicolas Tsiftes Date: Fri, 4 May 2018 18:12:10 +0200 Subject: [PATCH 110/129] Use a default Coffee file reservation size in Antelope that is selected in relation to the file system size. --- os/storage/antelope/db-options.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/os/storage/antelope/db-options.h b/os/storage/antelope/db-options.h index f82c72edc..2be415f4e 100644 --- a/os/storage/antelope/db-options.h +++ b/os/storage/antelope/db-options.h @@ -38,6 +38,7 @@ #define DB_OPTIONS_H #include "contiki.h" +#include "cfs-coffee-arch.h" /*----------------------------------------------------------------------------*/ @@ -143,9 +144,17 @@ /* The default relation file size to reserve when using Coffee. */ #ifndef DB_COFFEE_RESERVE_SIZE -#define DB_COFFEE_RESERVE_SIZE (128 * 1024UL) +#define DB_COFFEE_RESERVE_SIZE (COFFEE_SIZE / 8) #endif /* DB_COFFEE_RESERVE_SIZE */ +/* + * Ensure that the default size of Coffee file reservations is suitable + * for the file system size. + */ +#if DB_COFFEE_RESERVE_SIZE > (COFFEE_SIZE / 2) +#error DB_COFFEE_RESERVE_SIZE is too large for the file system. +#endif + /* The maximum size of the physical storage of a tuple (labelled a "row" in Antelope's terminology. */ #ifndef DB_MAX_CHAR_SIZE_PER_ROW From 7aed97f51408f8b4b6f7ced58a65e2ea94f26f66 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 4 May 2018 19:15:03 +0200 Subject: [PATCH 111/129] Updated tinydtls submodule to latest version --- os/net/security/tinydtls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/security/tinydtls b/os/net/security/tinydtls index 5da931eeb..5ec7ad129 160000 --- a/os/net/security/tinydtls +++ b/os/net/security/tinydtls @@ -1 +1 @@ -Subproject commit 5da931eeb78d1cd4a1e0068a91de9b78bd3f66de +Subproject commit 5ec7ad12984eebf22a7eb5d779f24945db4829e2 From 65015761833b874115d1c5f0456489f0f5185c48 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 24 Apr 2018 11:42:26 -0700 Subject: [PATCH 112/129] RPL MRHOF: configurable max link metric and path cost --- os/net/routing/rpl-lite/rpl-mrhof.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/os/net/routing/rpl-lite/rpl-mrhof.c b/os/net/routing/rpl-lite/rpl-mrhof.c index a0b2546eb..31b448b53 100644 --- a/os/net/routing/rpl-lite/rpl-mrhof.c +++ b/os/net/routing/rpl-lite/rpl-mrhof.c @@ -72,10 +72,18 @@ /* Configuration parameters of RFC6719. Reject parents that have a higher * link metric than the following. The default value is 512. */ +#ifdef RPL_MRHOF_CONF_MAX_LINK_METRIC +#define MAX_LINK_METRIC RPL_MRHOF_CONF_MAX_LINK_METRIC +#else /* RPL_MRHOF_CONF_MAX_LINK_METRIC */ #define MAX_LINK_METRIC 512 /* Eq ETX of 4 */ +#endif /* RPL_MRHOF_CONF_MAX_LINK_METRIC */ /* Reject parents that have a higher path cost than the following. */ +#ifdef RPL_MRHOF_CONF_MAX_PATH_COST +#define MAX_PATH_COST RPL_MRHOF_CONF_MAX_PATH_COST +#else /* RPL_MRHOF_CONF_MAX_PATH_COST */ #define MAX_PATH_COST 32768 /* Eq path ETX of 256 */ +#endif /* RPL_MRHOF_CONF_MAX_PATH_COST */ #if !RPL_MRHOF_SQUARED_ETX /* Hysteresis of MRHOF: the rank must differ more than PARENT_SWITCH_THRESHOLD_DIV From 9194b65d229e0b5e560cd286db8c8753db482dcf Mon Sep 17 00:00:00 2001 From: MartenBE Date: Sun, 6 May 2018 21:05:54 +0200 Subject: [PATCH 113/129] Fixed typo for savetarget target in usage string --- Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.include b/Makefile.include index e5fb4f646..4fe43c265 100644 --- a/Makefile.include +++ b/Makefile.include @@ -400,7 +400,7 @@ usage: @echo "Miscellaneous targets:" @echo " targets Prints list of supported platforms" @echo " boards Prints a list of supported boards for TARGET" - @echo " savegtarget Saves TARGET and BOARD for future invocations of make" + @echo " savetarget Saves TARGET and BOARD for future invocations of make" @echo " savedefines Saves DEFINES for future invocations of make" @echo " clean Removes all compiled files for TARGET" @echo " distclean Removes all compiled files for all TARGETs" From fa54354d922f0aa3505ca22bfba9893bc33fd116 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Mon, 7 May 2018 06:51:09 +0200 Subject: [PATCH 114/129] Updated lwm2m-ipso-object server-example for latest RPL/CoAP APIs --- examples/lwm2m-ipso-objects/Makefile | 13 -- examples/lwm2m-ipso-objects/README.md | 4 +- examples/lwm2m-ipso-objects/example-server.c | 197 +++++++++--------- examples/lwm2m-ipso-objects/serial-protocol.c | 6 +- 4 files changed, 110 insertions(+), 110 deletions(-) diff --git a/examples/lwm2m-ipso-objects/Makefile b/examples/lwm2m-ipso-objects/Makefile index d77f4200a..7fa79d1ee 100644 --- a/examples/lwm2m-ipso-objects/Makefile +++ b/examples/lwm2m-ipso-objects/Makefile @@ -12,16 +12,3 @@ MODULES += os/services/ipso-objects CONTIKI=../.. include $(CONTIKI)/Makefile.include - -# border router rules -$(CONTIKI)/tools/tunslip6: $(CONTIKI)/tools/tunslip6.c - (cd $(CONTIKI)/tools && $(MAKE) tunslip6) - -connect-router: $(CONTIKI)/tools/tunslip6 - sudo $(CONTIKI)/tools/tunslip6 aaaa::1/64 - -connect-router-cooja: $(CONTIKI)/tools/tunslip6 - sudo $(CONTIKI)/tools/tunslip6 -a 127.0.0.1 -p 60001 aaaa::1/64 - -connect-router-native: $(CONTIKI)/examples/native-border-router/border-router.native - sudo $(CONTIKI)/examples/native-border-router/border-router.native -a 127.0.0.1 -p 60001 aaaa::1/64 diff --git a/examples/lwm2m-ipso-objects/README.md b/examples/lwm2m-ipso-objects/README.md index 30cc5832f..d31b3a844 100644 --- a/examples/lwm2m-ipso-objects/README.md +++ b/examples/lwm2m-ipso-objects/README.md @@ -3,8 +3,8 @@ LWM2M with IPSO Objects Example This is an OMA LWM2M example implementing IPSO Objects. It can connect to a Leshan server out-of-the-box. -Important configuration paramters: -* `LWM2M_SERVER_ADDRESS`: the address of the server to register to (or bosstrap from) +Important configuration parameters: +* `LWM2M_SERVER_ADDRESS`: the address of the server to register to (or bootstrap from) * `REGISTER_WITH_LWM2M_BOOTSTRAP_SERVER`: set to bootstrap via `LWM2M_SERVER_ADDRESS` and then obtain the registration server address A tutorial for setting up this example is provided on the wiki. diff --git a/examples/lwm2m-ipso-objects/example-server.c b/examples/lwm2m-ipso-objects/example-server.c index 4eac38f69..0b55b80a2 100644 --- a/examples/lwm2m-ipso-objects/example-server.c +++ b/examples/lwm2m-ipso-objects/example-server.c @@ -38,19 +38,23 @@ #include "contiki.h" #include "net/ipv6/uip.h" +#include "net/ipv6/uip-ds6.h" #include "net/netstack.h" #include "net/routing/routing.h" -#include "coap-constants.h" -#include "coap-engine.h" +#include "coap-transport.h" +#include "coap-blocking-api.h" #include "lwm2m-engine.h" #include "lwm2m-tlv.h" #include "dev/serial-line.h" #include "serial-protocol.h" +#include #define DEBUG DEBUG_PRINT #include "net/ipv6/uip-debug.h" -#define REMOTE_PORT UIP_HTONS(COAP_DEFAULT_PORT) +#define REMOTE_PORT UIP_HTONS(COAP_DEFAULT_PORT) + +#define EVENT_RUN_NOW 0 #define URL_WELL_KNOWN ".well-known/core" #define URL_DEVICE_MODEL "/3/0/1" @@ -63,8 +67,8 @@ #define NODE_HAS_TYPE (1 << 0) struct node { - uip_ipaddr_t ipaddr; - char type[32]; + coap_endpoint_t endpoint; + char type[64]; uint8_t flags; uint8_t retries; }; @@ -86,13 +90,15 @@ add_node(const uip_ipaddr_t *addr) { int i; for(i = 0; i < node_count; i++) { - if(uip_ipaddr_cmp(&nodes[i].ipaddr, addr)) { + if(uip_ipaddr_cmp(&nodes[i].endpoint.ipaddr, addr)) { /* Node already added */ return &nodes[i]; } } if(node_count < MAX_NODES) { - uip_ipaddr_copy(&nodes[node_count].ipaddr, addr); + memset(&nodes[node_count].endpoint, 0, sizeof(coap_endpoint_t)); + uip_ipaddr_copy(&nodes[node_count].endpoint.ipaddr, addr); + nodes[node_count].endpoint.port = REMOTE_PORT; return &nodes[node_count++]; } return NULL; @@ -107,13 +113,13 @@ set_value(const uip_ipaddr_t *addr, char *uri, char *value) printf(" URI: %s Value: %s\n", uri, value); for(i = 0; i < node_count; i++) { - if(uip_ipaddr_cmp(&nodes[i].ipaddr, addr)) { + if(uip_ipaddr_cmp(&nodes[i].endpoint.ipaddr, addr)) { /* setup command */ current_target = &nodes[i]; current_request = COAP_PUT; strncpy(current_uri, uri, sizeof(current_uri) - 1); strncpy(current_value, value, sizeof(current_value) - 1); - process_poll(&router_process); + process_post(&router_process, EVENT_RUN_NOW, NULL); break; } } @@ -128,13 +134,13 @@ get_value(const uip_ipaddr_t *addr, char *uri) printf(" URI: %s\n", uri); for(i = 0; i < node_count; i++) { - if(uip_ipaddr_cmp(&nodes[i].ipaddr, addr)) { + if(uip_ipaddr_cmp(&nodes[i].endpoint.ipaddr, addr)) { /* setup command */ current_target = &nodes[i]; current_request = COAP_GET; strncpy(current_uri, uri, sizeof(current_uri) - 1); current_value[0] = 0; - process_poll(&router_process); + process_post(&router_process, EVENT_RUN_NOW, NULL); break; } } @@ -151,7 +157,7 @@ print_node_list(void) printf(";"); } printf("%s,", nodes[i].type); - uip_debug_ipaddr_print(&nodes[i].ipaddr); + uip_debug_ipaddr_print(&nodes[i].endpoint.ipaddr); } } printf("\n"); @@ -162,7 +168,7 @@ print_node_list(void) * handle responses. */ static void -client_chunk_handler(void *response) +client_chunk_handler(coap_message_t *response) { const uint8_t *chunk; unsigned int format; @@ -172,7 +178,9 @@ client_chunk_handler(void *response) /* if(len > 0) { */ /* printf("|%.*s (%d,%d)", len, (char *)chunk, len, format); */ /* } */ - if(current_target != NULL && fetching_type) { + if(response->code >= BAD_REQUEST_4_00) { + PRINTF("\nReceived error %u: %.*s\n", response->code, len, (char *)chunk); + } else if(current_target != NULL && fetching_type) { if(len > sizeof(current_target->type) - 1) { len = sizeof(current_target->type) - 1; } @@ -181,7 +189,7 @@ client_chunk_handler(void *response) current_target->flags |= NODE_HAS_TYPE; PRINTF("\nNODE "); - PRINT6ADDR(¤t_target->ipaddr); + PRINT6ADDR(¤t_target->endpoint.ipaddr); PRINTF(" HAS TYPE %s\n", current_target->type); } else { /* otherwise update the current value */ @@ -193,7 +201,9 @@ client_chunk_handler(void *response) /* tlv.type, tlv.length, tlv.id, tlv.value[0]); */ int value = lwm2m_tlv_get_int32(&tlv); - snprintf(current_value, sizeof(current_value), "%d", value); + snprintf(current_value, sizeof(current_value) - 1, "%d", value); + } else { + PRINTF("Failed to parse LWM2M TLV\n"); } } else { if(len > sizeof(current_value) - 1) { @@ -205,72 +215,84 @@ client_chunk_handler(void *response) } } /*---------------------------------------------------------------------------*/ -static void -setup_network(void) +#if UIP_CONF_IPV6_RPL +static bool +check_rpl_routes(void) { - uip_ipaddr_t ipaddr; - struct uip_ds6_addr *root_if; - rpl_dag_t *dag; - int i; - uint8_t state; + uip_sr_node_t *link; + uip_ipaddr_t child_ipaddr; + uip_ipaddr_t parent_ipaddr; -#if UIP_CONF_ROUTER -/** - * The choice of server address determines its 6LoWPAN header compression. - * Obviously the choice made here must also be selected in udp-client.c. - * - * For correct Wireshark decoding using a sniffer, add the /64 prefix to the 6LowPAN protocol preferences, - * e.g. set Context 0 to fd00::. At present Wireshark copies Context/128 and then overwrites it. - * (Setting Context 0 to fd00::1111:2222:3333:4444 will report a 16 bit compressed address of fd00::1111:22ff:fe33:xxxx) - * Note Wireshark's IPCMV6 checksum verification depends on the correct uncompressed addresses. - */ -#if 0 -/* Mode 1 - 64 bits inline */ - uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 1); -#elif 1 -/* Mode 2 - 16 bits inline */ - uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0x00ff, 0xfe00, 1); -#else -/* Mode 3 - derived from link local (MAC) address */ - uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0); - uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); -#endif + /* Our routing links */ + for(link = uip_sr_node_head(); link != NULL; link = uip_sr_node_next(link)) { + NETSTACK_ROUTING.get_sr_node_ipaddr(&child_ipaddr, link); - NETSTACK_ROUTING.root_set_prefix(&ipaddr, &ipaddr); - NETSTACK_ROUTING.root_start(); -#endif /* UIP_CONF_ROUTER */ - - PRINTF("IPv6 addresses: "); - for(i = 0; i < UIP_DS6_ADDR_NB; i++) { - state = uip_ds6_if.addr_list[i].state; - if(state == ADDR_TENTATIVE || state == ADDR_PREFERRED) { - PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr); - PRINTF("\n"); - /* hack to make address "final" */ - if (state == ADDR_TENTATIVE) { - uip_ds6_if.addr_list[i].state = ADDR_PREFERRED; - } + if(link->parent == NULL) { + /* Igore the DAG root */ + continue; } + + current_target = add_node(&child_ipaddr); + if(current_target == NULL || + (current_target->flags & NODE_HAS_TYPE) != 0 || + current_target->retries > 5) { + continue; + } + + NETSTACK_ROUTING.get_sr_node_ipaddr(&parent_ipaddr, link->parent); + PRINTF(" "); + PRINT6ADDR(&child_ipaddr); + PRINTF(" -> "); + PRINT6ADDR(&parent_ipaddr); + PRINTF("\n"); + return true; } + return false; } +#endif /* UIP_CONF_IPV6_RPL */ +/*---------------------------------------------------------------------------*/ +#if (UIP_MAX_ROUTES != 0) +static bool +check_routes(void) +{ + uip_ds6_route_t *r; + + for(r = uip_ds6_route_head(); r != NULL; r = uip_ds6_route_next(r)) { + current_target = add_node(&r->ipaddr); + if(current_target == NULL || + (current_target->flags & NODE_HAS_TYPE) != 0 || + current_target->retries > 5) { + continue; + } + PRINTF(" "); + PRINT6ADDR(&r->ipaddr); + PRINTF(" -> "); + nexthop = uip_ds6_route_nexthop(r); + if(nexthop != NULL) { + PRINT6ADDR(nexthop); + } else { + PRINTF("-"); + } + PRINTF("\n"); + return true; + } + return false; +} +#endif /* (UIP_MAX_ROUTES != 0) */ /*---------------------------------------------------------------------------*/ PROCESS_THREAD(router_process, ev, data) { /* This way the message can be treated as pointer as usual. */ static coap_message_t request[1]; static struct etimer timer; - uip_ds6_route_t *r; - uip_ipaddr_t *nexthop; - int n; PROCESS_BEGIN(); - PROCESS_PAUSE(); - /* receives all CoAP messages */ coap_engine_init(); - setup_network(); + /* Initialize DAG root */ + NETSTACK_ROUTING.root_start(); while(1) { etimer_set(&timer, CLOCK_SECOND * 5); @@ -283,28 +305,15 @@ PROCESS_THREAD(router_process, ev, data) if(etimer_expired(&timer)) { current_target = NULL; - n = 0; - for(r = uip_ds6_route_head(); r != NULL; r = uip_ds6_route_next(r)) { - current_target = add_node(&r->ipaddr); - if(current_target == NULL || - (current_target->flags & NODE_HAS_TYPE) != 0 || - current_target->retries > 5) { - continue; - } - PRINTF(" "); - PRINT6ADDR(&r->ipaddr); - PRINTF(" -> "); - nexthop = uip_ds6_route_nexthop(r); - if(nexthop != NULL) { - PRINT6ADDR(nexthop); - PRINTF("\n"); - } else { - PRINTF("-"); - } - PRINTF("\n"); - n++; - break; +#if UIP_CONF_IPV6_RPL + check_rpl_routes(); +#endif /* UIP_CONF_IPV6_RPL */ + +#if (UIP_MAX_ROUTES != 0) + if(current_target == NULL) { + check_routes(); } +#endif /* (UIP_MAX_ROUTES != 0) */ } /* This is a node type discovery */ @@ -319,15 +328,15 @@ PROCESS_THREAD(router_process, ev, data) current_target->retries++; PRINTF("CoAP request to ["); - PRINT6ADDR(¤t_target->ipaddr); - PRINTF("]:%u (%u tx)\n", UIP_HTONS(REMOTE_PORT), + PRINT6ADDR(¤t_target->endpoint.ipaddr); + PRINTF("]:%u (%u tx)\n", UIP_HTONS(current_target->endpoint.port), current_target->retries); fetching_type = 1; - COAP_BLOCKING_REQUEST(¤t_target->ipaddr, REMOTE_PORT, request, + COAP_BLOCKING_REQUEST(¤t_target->endpoint, request, client_chunk_handler); fetching_type = 0; - strncpy(current_uri, URL_LIGHT_CONTROL, sizeof(current_uri)); + strncpy(current_uri, URL_LIGHT_CONTROL, sizeof(current_uri) - 1); printf("\n--Done--\n"); } @@ -344,10 +353,11 @@ PROCESS_THREAD(router_process, ev, data) } PRINTF("CoAP request to ["); - PRINT6ADDR(¤t_target->ipaddr); - PRINTF("]:%u %s\n", UIP_HTONS(REMOTE_PORT), current_uri); + PRINT6ADDR(¤t_target->endpoint.ipaddr); + PRINTF("]:%u %s\n", UIP_HTONS(current_target->endpoint.port), + current_uri); - COAP_BLOCKING_REQUEST(¤t_target->ipaddr, REMOTE_PORT, request, + COAP_BLOCKING_REQUEST(¤t_target->endpoint, request, client_chunk_handler); /* print out result of command */ @@ -356,13 +366,12 @@ PROCESS_THREAD(router_process, ev, data) } else { printf("g "); } - uip_debug_ipaddr_print(¤t_target->ipaddr); + uip_debug_ipaddr_print(¤t_target->endpoint.ipaddr); printf(" %s %s\n", current_uri, current_value); current_target = NULL; current_uri[0] = 0; current_value[0] = 0; - } } diff --git a/examples/lwm2m-ipso-objects/serial-protocol.c b/examples/lwm2m-ipso-objects/serial-protocol.c index bc59294f6..00c7e0139 100644 --- a/examples/lwm2m-ipso-objects/serial-protocol.c +++ b/examples/lwm2m-ipso-objects/serial-protocol.c @@ -60,7 +60,7 @@ find_next_sep(const char *str, char sep, int pos) /* * l - list all discovered devices * s - set - * d - get + * g - get */ void serial_protocol_input(char *data) @@ -119,8 +119,12 @@ serial_protocol_input(char *data) } break; } + case '\0': + /* Ignore empty lines */ + break; default: printf("Unknown command\n"); } + printf("> "); } /*---------------------------------------------------------------------------*/ From f2394720c8842cb91f5c1879de5f94cc78b69642 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 6 May 2018 04:13:49 -0700 Subject: [PATCH 115/129] Makefile.include: include nullnet only when using MAKE_MAC_NULLNET --- Makefile.include | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile.include b/Makefile.include index e5fb4f646..1650bc60c 100644 --- a/Makefile.include +++ b/Makefile.include @@ -167,14 +167,12 @@ MAKE_NET ?= MAKE_NET_IPV6 ifeq ($(MAKE_NET),MAKE_NET_NULLNET) CFLAGS += -DNETSTACK_CONF_WITH_NULLNET=1 + MODULES += os/net/nullnet endif ifeq ($(MAKE_NET),MAKE_NET_IPV6) CFLAGS += -DNETSTACK_CONF_WITH_IPV6=1 MODULES += os/net/ipv6 -else - CFLAGS += -DNETSTACK_CONF_WITH_NULLNET=1 - MODULES += os/net/nullnet endif ifeq ($(MAKE_NET),MAKE_NET_OTHER) From a2d9093cefe473e2e1621ca94a9d79d15192c844 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 9 May 2018 14:38:59 -0700 Subject: [PATCH 116/129] RPL Lite: make sure no more than one probe gets in queue at any given time --- os/net/routing/rpl-lite/rpl-neighbor.c | 4 +++- os/net/routing/rpl-lite/rpl-timers.c | 19 +++++++++++-------- os/net/routing/rpl-lite/rpl-timers.h | 5 +++++ os/net/routing/rpl-lite/rpl.c | 5 +++++ 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/os/net/routing/rpl-lite/rpl-neighbor.c b/os/net/routing/rpl-lite/rpl-neighbor.c index 8afa2440f..bd0632778 100644 --- a/os/net/routing/rpl-lite/rpl-neighbor.c +++ b/os/net/routing/rpl-lite/rpl-neighbor.c @@ -368,6 +368,8 @@ rpl_neighbor_select_best(void) #if RPL_WITH_PROBING if(best != NULL) { if(rpl_neighbor_is_fresh(best)) { + /* Unschedule any already scheduled urgent probing */ + curr_instance.dag.urgent_probing_target = NULL; /* Return best if it is fresh */ return best; } else { @@ -380,7 +382,7 @@ rpl_neighbor_select_best(void) LOG_WARN_6ADDR(rpl_neighbor_get_ipaddr(best)); LOG_WARN_("\n"); curr_instance.dag.urgent_probing_target = best; - rpl_schedule_probing(); + rpl_schedule_probing_now(); } /* The best is our preferred parent. It is not fresh but used to be, diff --git a/os/net/routing/rpl-lite/rpl-timers.c b/os/net/routing/rpl-lite/rpl-timers.c index 5b4ab8faa..6fb00ca17 100644 --- a/os/net/routing/rpl-lite/rpl-timers.c +++ b/os/net/routing/rpl-lite/rpl-timers.c @@ -342,13 +342,7 @@ handle_dao_ack_timer(void *ptr) clock_time_t get_probing_delay(void) { - if(curr_instance.used && curr_instance.dag.urgent_probing_target != NULL) { - /* Urgent probing needed (to find out if a neighbor may become preferred parent) */ - return random_rand() % (CLOCK_SECOND * 4); - } else { - /* Else, use normal probing interval */ - return ((RPL_PROBING_INTERVAL) / 2) + random_rand() % (RPL_PROBING_INTERVAL); - } + return ((RPL_PROBING_INTERVAL) / 2) + random_rand() % (RPL_PROBING_INTERVAL); } /*---------------------------------------------------------------------------*/ rpl_nbr_t * @@ -440,7 +434,7 @@ handle_probing_timer(void *ptr) ); /* Send probe, e.g. unicast DIO or DIS */ RPL_PROBING_SEND_FUNC(target_ipaddr); - curr_instance.dag.urgent_probing_target = NULL; + /* urgent_probing_target will be NULLed in the packet_sent callback */ } else { LOG_INFO("no neighbor needs probing\n"); } @@ -457,6 +451,15 @@ rpl_schedule_probing(void) handle_probing_timer, NULL); } } +/*---------------------------------------------------------------------------*/ +void +rpl_schedule_probing_now(void) +{ + if(curr_instance.used) { + ctimer_set(&curr_instance.dag.probing_timer, + random_rand() % (CLOCK_SECOND * 4), handle_probing_timer, NULL); + } +} #endif /* RPL_WITH_PROBING */ /*---------------------------------------------------------------------------*/ /*------------------------------- Leaving-- -------------------------------- */ diff --git a/os/net/routing/rpl-lite/rpl-timers.h b/os/net/routing/rpl-lite/rpl-timers.h index 884a55696..e153858fc 100644 --- a/os/net/routing/rpl-lite/rpl-timers.h +++ b/os/net/routing/rpl-lite/rpl-timers.h @@ -104,6 +104,11 @@ void rpl_timers_schedule_dao_ack(uip_ipaddr_t *target, uint16_t sequence); */ void rpl_schedule_probing(void); +/** + * Schedule probing within a few seconds +*/ +void rpl_schedule_probing_now(void); + /** * Schedule a state update ASAP. Useful to force an update from a context * where updating directly would be unsafe. diff --git a/os/net/routing/rpl-lite/rpl.c b/os/net/routing/rpl-lite/rpl.c index fd93b40e8..47ffc5387 100644 --- a/os/net/routing/rpl-lite/rpl.c +++ b/os/net/routing/rpl-lite/rpl.c @@ -99,6 +99,11 @@ rpl_link_callback(const linkaddr_t *addr, int status, int numtx) if(curr_instance.used == 1 ) { rpl_nbr_t *nbr = rpl_neighbor_get_from_lladdr((uip_lladdr_t *)addr); if(nbr != NULL) { + /* If this is the neighbor we were probing urgently, mark urgent + probing as done */ + if(curr_instance.dag.urgent_probing_target == nbr) { + curr_instance.dag.urgent_probing_target = NULL; + } /* Link stats were updated, and we need to update our internal state. Updating from here is unsafe; postpone */ LOG_INFO("packet sent to "); From 72f558fb6e8a46da1d0c59537516bc1110c6f62f Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 9 May 2018 14:39:14 -0700 Subject: [PATCH 117/129] RPL Classic: make sure no more than one probe gets in queue at any given time --- os/net/routing/rpl-classic/rpl-dag.c | 4 +++- os/net/routing/rpl-classic/rpl-private.h | 1 + os/net/routing/rpl-classic/rpl-timers.c | 17 ++++++++--------- os/net/routing/rpl-classic/rpl.c | 5 +++++ 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/os/net/routing/rpl-classic/rpl-dag.c b/os/net/routing/rpl-classic/rpl-dag.c index 742ef16c4..670a54f3f 100644 --- a/os/net/routing/rpl-classic/rpl-dag.c +++ b/os/net/routing/rpl-classic/rpl-dag.c @@ -908,6 +908,8 @@ rpl_select_parent(rpl_dag_t *dag) #if RPL_WITH_PROBING if(rpl_parent_is_fresh(best)) { rpl_set_preferred_parent(dag, best); + /* Unschedule any already scheduled urgent probing */ + dag->instance->urgent_probing_target = NULL; } else { /* The best is not fresh. Look for the best fresh now. */ rpl_parent_t *best_fresh = best_parent(dag, 1); @@ -920,7 +922,7 @@ rpl_select_parent(rpl_dag_t *dag) } /* Probe the best parent shortly in order to get a fresh estimate */ dag->instance->urgent_probing_target = best; - rpl_schedule_probing(dag->instance); + rpl_schedule_probing_now(dag->instance); } #else /* RPL_WITH_PROBING */ rpl_set_preferred_parent(dag, best); diff --git a/os/net/routing/rpl-classic/rpl-private.h b/os/net/routing/rpl-classic/rpl-private.h index 1259fffeb..5a01c538a 100644 --- a/os/net/routing/rpl-classic/rpl-private.h +++ b/os/net/routing/rpl-classic/rpl-private.h @@ -341,6 +341,7 @@ void rpl_schedule_dao_immediately(rpl_instance_t *); void rpl_schedule_unicast_dio_immediately(rpl_instance_t *instance); void rpl_cancel_dao(rpl_instance_t *instance); void rpl_schedule_probing(rpl_instance_t *instance); +void rpl_schedule_probing_now(rpl_instance_t *instance); void rpl_reset_dio_timer(rpl_instance_t *); void rpl_reset_periodic_timer(void); diff --git a/os/net/routing/rpl-classic/rpl-timers.c b/os/net/routing/rpl-classic/rpl-timers.c index c812a8897..97233f574 100644 --- a/os/net/routing/rpl-classic/rpl-timers.c +++ b/os/net/routing/rpl-classic/rpl-timers.c @@ -380,14 +380,7 @@ rpl_schedule_unicast_dio_immediately(rpl_instance_t *instance) clock_time_t get_probing_delay(rpl_dag_t *dag) { - if(dag != NULL && dag->instance != NULL - && dag->instance->urgent_probing_target != NULL) { - /* Urgent probing needed (to find out if a neighbor may become preferred parent) */ - return random_rand() % (CLOCK_SECOND * 10); - } else { - /* Else, use normal probing interval */ - return ((RPL_PROBING_INTERVAL) / 2) + random_rand() % (RPL_PROBING_INTERVAL); - } + return ((RPL_PROBING_INTERVAL) / 2) + random_rand() % (RPL_PROBING_INTERVAL); } /*---------------------------------------------------------------------------*/ rpl_parent_t * @@ -494,7 +487,6 @@ handle_probing_timer(void *ptr) ); /* Send probe, e.g. unicast DIO or DIS */ RPL_PROBING_SEND_FUNC(instance, target_ipaddr); - instance->urgent_probing_target = NULL; } /* Schedule next probing */ @@ -511,5 +503,12 @@ rpl_schedule_probing(rpl_instance_t *instance) ctimer_set(&instance->probing_timer, RPL_PROBING_DELAY_FUNC(instance->current_dag), handle_probing_timer, instance); } +/*---------------------------------------------------------------------------*/ +void +rpl_schedule_probing_now(rpl_instance_t *instance) +{ + ctimer_set(&instance->probing_timer, random_rand() % (CLOCK_SECOND * 4), + handle_probing_timer, instance); +} #endif /* RPL_WITH_PROBING */ /** @}*/ diff --git a/os/net/routing/rpl-classic/rpl.c b/os/net/routing/rpl-classic/rpl.c index b1905d611..ecbcdc158 100644 --- a/os/net/routing/rpl-classic/rpl.c +++ b/os/net/routing/rpl-classic/rpl.c @@ -266,6 +266,11 @@ rpl_link_callback(const linkaddr_t *addr, int status, int numtx) if(instance->used == 1 ) { parent = rpl_find_parent_any_dag(instance, &ipaddr); if(parent != NULL) { + /* If this is the neighbor we were probing urgently, mark urgent + probing as done */ + if(instance->urgent_probing_target == parent) { + instance->urgent_probing_target = NULL; + } /* Trigger DAG rank recalculation. */ PRINTF("RPL: rpl_link_callback triggering update\n"); parent->flags |= RPL_PARENT_FLAG_UPDATED; From 51a4960fa85a9006e3b7c61dc219881eb9fa940e Mon Sep 17 00:00:00 2001 From: Antonio Iannopollo Date: Wed, 9 May 2018 19:25:08 -0700 Subject: [PATCH 118/129] fixed dht22 driver and example --- arch/platform/zoul/dev/dht22.c | 3 +-- arch/platform/zoul/dev/dht22.h | 2 +- examples/platform-specific/zoul/test-dht22.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/platform/zoul/dev/dht22.c b/arch/platform/zoul/dev/dht22.c index f12859dff..0e826bfbf 100644 --- a/arch/platform/zoul/dev/dht22.c +++ b/arch/platform/zoul/dev/dht22.c @@ -72,7 +72,7 @@ dht22_read(void) { uint8_t i; uint8_t j = 0; - uint8_t last_state; + uint8_t last_state = 0xFF; uint8_t counter = 0; uint8_t checksum = 0; @@ -95,7 +95,6 @@ dht22_read(void) * if the line is high between 70-74us the bit sent will be "1" (one). */ GPIO_SET_INPUT(DHT22_PORT_BASE, DHT22_PIN_MASK); - last_state = GPIO_READ_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK); for(i = 0; i < DHT22_MAX_TIMMING; i++) { counter = 0; diff --git a/arch/platform/zoul/dev/dht22.h b/arch/platform/zoul/dev/dht22.h index f75a96494..10adee5c3 100644 --- a/arch/platform/zoul/dev/dht22.h +++ b/arch/platform/zoul/dev/dht22.h @@ -90,7 +90,7 @@ #define DHT22_COUNT 8 /**< Minimum ticks to detect a "1" bit */ #define DHT22_MAX_TIMMING 85 /**< Maximum ticks in a single operation */ #define DHT22_READING_DELAY 1 /**< 1 us */ -#define DHT22_READY_TIME 20 /**< 40 us */ +#define DHT22_READY_TIME 40 /**< 40 us */ #define DHT22_START_TIME (RTIMER_SECOND / 50) /**< 20 ms */ #define DHT22_AWAKE_TIME (RTIMER_SECOND / 4) /**< 250 ms */ /** @} */ diff --git a/examples/platform-specific/zoul/test-dht22.c b/examples/platform-specific/zoul/test-dht22.c index 43048eba3..f1a49b516 100644 --- a/examples/platform-specific/zoul/test-dht22.c +++ b/examples/platform-specific/zoul/test-dht22.c @@ -55,7 +55,7 @@ static struct etimer et; /*---------------------------------------------------------------------------*/ PROCESS_THREAD(remote_dht22_process, ev, data) { - int16_t temperature, humidity; + int temperature, humidity; PROCESS_BEGIN(); SENSORS_ACTIVATE(dht22); From 0b9f03f442b5c3bc255cceab2b2f98983a0fe5c8 Mon Sep 17 00:00:00 2001 From: Antonio Iannopollo Date: Wed, 9 May 2018 19:29:24 -0700 Subject: [PATCH 119/129] fixed dht22 driver --- arch/platform/zoul/dev/dht22.c | 4 ++-- arch/platform/zoul/dev/dht22.h | 2 +- examples/platform-specific/zoul/test-dht22.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/platform/zoul/dev/dht22.c b/arch/platform/zoul/dev/dht22.c index 0e826bfbf..e5d14d53b 100644 --- a/arch/platform/zoul/dev/dht22.c +++ b/arch/platform/zoul/dev/dht22.c @@ -207,8 +207,8 @@ value(int type) } } /*---------------------------------------------------------------------------*/ -int -dht22_read_all(int *temperature, int *humidity) +int16_t +dht22_read_all(int16_t *temperature, int16_t *humidity) { if((temperature == NULL) || (humidity == NULL)) { PRINTF("DHT22: Invalid arguments\n"); diff --git a/arch/platform/zoul/dev/dht22.h b/arch/platform/zoul/dev/dht22.h index 10adee5c3..ecd02a26e 100644 --- a/arch/platform/zoul/dev/dht22.h +++ b/arch/platform/zoul/dev/dht22.h @@ -99,7 +99,7 @@ * \name DHT22 auxiliary functions * @{ */ -int dht22_read_all(int *temperature, int *humidity); +int16_t dht22_read_all(int16_t *temperature, int16_t *humidity); /** @} */ /* -------------------------------------------------------------------------- */ #define DHT22_SENSOR "DHT22 sensor" diff --git a/examples/platform-specific/zoul/test-dht22.c b/examples/platform-specific/zoul/test-dht22.c index f1a49b516..43048eba3 100644 --- a/examples/platform-specific/zoul/test-dht22.c +++ b/examples/platform-specific/zoul/test-dht22.c @@ -55,7 +55,7 @@ static struct etimer et; /*---------------------------------------------------------------------------*/ PROCESS_THREAD(remote_dht22_process, ev, data) { - int temperature, humidity; + int16_t temperature, humidity; PROCESS_BEGIN(); SENSORS_ACTIVATE(dht22); From 32578321cbd2db9193a29ecb45b22bf2d90aa5ed Mon Sep 17 00:00:00 2001 From: Antonio Iannopollo Date: Thu, 10 May 2018 10:33:53 -0700 Subject: [PATCH 120/129] removed problematic .c extension in Makefile --- examples/platform-specific/zoul/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/platform-specific/zoul/Makefile b/examples/platform-specific/zoul/Makefile index 88dcb3ce2..3b57eb035 100644 --- a/examples/platform-specific/zoul/Makefile +++ b/examples/platform-specific/zoul/Makefile @@ -1,9 +1,9 @@ -CONTIKI_PROJECT = test-tsl256x test-sht25 test-servo.c +CONTIKI_PROJECT = test-tsl256x test-sht25 test-servo CONTIKI_PROJECT += test-bmp085-bmp180 test-motion test-rotation-sensor CONTIKI_PROJECT += test-grove-light-sensor test-grove-loudness-sensor CONTIKI_PROJECT += test-weather-meter test-grove-gyro test-lcd test-iaq CONTIKI_PROJECT += test-pm10-sensor test-vac-sensor test-aac-sensor -CONTIKI_PROJECT += test-zonik test-dht22.c test-ac-dimmer.c +CONTIKI_PROJECT += test-zonik test-dht22 test-ac-dimmer CONTIKI_PROJECT += test-bme280 CONTIKI_TARGET_SOURCEFILES += tsl256x.c sht25.c bmpx8x.c motion-sensor.c From 6aa17cce95c1f084af9cb2786c51ee71ccb7dbd1 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 9 May 2018 15:29:41 -0700 Subject: [PATCH 121/129] RPL Lite: disable MRHOF ETX squaring by default --- os/net/routing/rpl-classic/rpl-mrhof.c | 17 +++++++++++------ os/net/routing/rpl-lite/rpl-mrhof.c | 19 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/os/net/routing/rpl-classic/rpl-mrhof.c b/os/net/routing/rpl-classic/rpl-mrhof.c index 4f5189384..f3c75985b 100644 --- a/os/net/routing/rpl-classic/rpl-mrhof.c +++ b/os/net/routing/rpl-classic/rpl-mrhof.c @@ -56,14 +56,19 @@ /* RFC6551 and RFC6719 do not mandate the use of a specific formula to * compute the ETX value. This MRHOF implementation relies on the value - * computed by the link-stats module. It has an optional feature, + * computed by the link-stats module.It has an optional feature, * RPL_MRHOF_CONF_SQUARED_ETX, that consists in squaring this value. - * This basically penalizes bad links while preserving the semantics of ETX + * + * Squaring basically penalizes bad links while preserving the semantics of ETX * (1 = perfect link, more = worse link). As a result, MRHOF will favor - * good links over short paths. Recommended when reliability is a priority. - * Without this feature, a hop with 50% PRR (ETX=2) is equivalent to two - * perfect hops with 100% PRR (ETX=1+1=2). With this feature, the former - * path obtains ETX=2*2=4 and the former ETX=1*1+1*1=2. */ + * good links over short paths. Without this feature, a hop with 50% PRR (ETX=2) + * is equivalent to two perfect hops with 100% PRR (ETX=1+1=2). With this + * feature, the former path obtains ETX=2*2=4 and the former ETX=1*1+1*1=2. + * + * While this feature helps achieve extra relaibility, it also results in + * added churn. In networks with high congestion or poor links, this can lead + * to poor connectivity due to more parent switches, loops, Trickle resets, etc. + */ #ifdef RPL_MRHOF_CONF_SQUARED_ETX #define RPL_MRHOF_SQUARED_ETX RPL_MRHOF_CONF_SQUARED_ETX #else /* RPL_MRHOF_CONF_SQUARED_ETX */ diff --git a/os/net/routing/rpl-lite/rpl-mrhof.c b/os/net/routing/rpl-lite/rpl-mrhof.c index a0b2546eb..5504f4fda 100644 --- a/os/net/routing/rpl-lite/rpl-mrhof.c +++ b/os/net/routing/rpl-lite/rpl-mrhof.c @@ -56,18 +56,23 @@ /* RFC6551 and RFC6719 do not mandate the use of a specific formula to * compute the ETX value. This MRHOF implementation relies on the value - * computed by the link-stats module. It has an optional feature, + * computed by the link-stats module.It has an optional feature, * RPL_MRHOF_CONF_SQUARED_ETX, that consists in squaring this value. - * This basically penalizes bad links while preserving the semantics of ETX + * + * Squaring basically penalizes bad links while preserving the semantics of ETX * (1 = perfect link, more = worse link). As a result, MRHOF will favor - * good links over short paths. Recommended when reliability is a priority. - * Without this feature, a hop with 50% PRR (ETX=2) is equivalent to two - * perfect hops with 100% PRR (ETX=1+1=2). With this feature, the former - * path obtains ETX=2*2=4 and the former ETX=1*1+1*1=2. */ + * good links over short paths. Without this feature, a hop with 50% PRR (ETX=2) + * is equivalent to two perfect hops with 100% PRR (ETX=1+1=2). With this + * feature, the former path obtains ETX=2*2=4 and the former ETX=1*1+1*1=2. + * + * While this feature helps achieve extra relaibility, it also results in + * added churn. In networks with high congestion or poor links, this can lead + * to poor connectivity due to more parent switches, loops, Trickle resets, etc. + */ #ifdef RPL_MRHOF_CONF_SQUARED_ETX #define RPL_MRHOF_SQUARED_ETX RPL_MRHOF_CONF_SQUARED_ETX #else /* RPL_MRHOF_CONF_SQUARED_ETX */ -#define RPL_MRHOF_SQUARED_ETX 1 +#define RPL_MRHOF_SQUARED_ETX 0 #endif /* RPL_MRHOF_CONF_SQUARED_ETX */ /* Configuration parameters of RFC6719. Reject parents that have a higher From 73bc179cebf6acaac4fc9bae42438767ce5b46b3 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 9 May 2018 23:49:15 -0700 Subject: [PATCH 122/129] link-stat: increase penalty applied in case of no-ack --- os/net/link-stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/net/link-stats.c b/os/net/link-stats.c index 60b107aec..fbb7677da 100644 --- a/os/net/link-stats.c +++ b/os/net/link-stats.c @@ -64,7 +64,7 @@ /* ETX fixed point divisor. 128 is the value used by RPL (RFC 6551 and RFC 6719) */ #define ETX_DIVISOR LINK_STATS_ETX_DIVISOR /* Number of Tx used to update the ETX EWMA in case of no-ACK */ -#define ETX_NOACK_PENALTY 16 +#define ETX_NOACK_PENALTY 20 /* Initial ETX value */ #define ETX_DEFAULT 2 From 21dd6209ff72538fe3cbef304a678470737e4c24 Mon Sep 17 00:00:00 2001 From: kkrentz Date: Tue, 24 Apr 2018 08:56:11 -0700 Subject: [PATCH 123/129] uip: Support for IEEE 802.15.4 short addresses --- arch/cpu/cc2538/ieee-addr.c | 7 ++----- examples/slip-radio/slip-radio.c | 2 +- os/net/ipv6/uip-ds6.c | 18 +++++++++++++----- os/net/ipv6/uip.h | 17 ++++++++++++----- .../rpl-border-router/embedded/slip-bridge.c | 2 +- .../native/border-router-cmds.c | 2 +- os/sys/log.c | 4 ++++ 7 files changed, 34 insertions(+), 18 deletions(-) diff --git a/arch/cpu/cc2538/ieee-addr.c b/arch/cpu/cc2538/ieee-addr.c index c914b511d..6a676f4eb 100644 --- a/arch/cpu/cc2538/ieee-addr.c +++ b/arch/cpu/cc2538/ieee-addr.c @@ -70,11 +70,8 @@ ieee_addr_cpy_to(uint8_t *dst, uint8_t len) if(((uint8_t *)IEEE_ADDR_LOCATION)[3] == oui_ti[0] && ((uint8_t *)IEEE_ADDR_LOCATION)[2] == oui_ti[1] && ((uint8_t *)IEEE_ADDR_LOCATION)[1] == oui_ti[2]) { - for(i = 0; i < len / 2; i++) { - dst[i] = ((uint8_t *)IEEE_ADDR_LOCATION)[len / 2 - 1 - i]; - } - for(i = 0; i < len / 2; i++) { - dst[i + len / 2] = ((uint8_t *)IEEE_ADDR_LOCATION)[len - 1 - i]; + for(i = 0; i < len; i++) { + dst[len - i - 1] = ((uint8_t *)IEEE_ADDR_LOCATION)[i < 4 ? i + 4 : i - 4]; } } else { for(i = 0; i < len; i++) { diff --git a/examples/slip-radio/slip-radio.c b/examples/slip-radio/slip-radio.c index b39032d96..d4e9db1cf 100644 --- a/examples/slip-radio/slip-radio.c +++ b/examples/slip-radio/slip-radio.c @@ -193,7 +193,7 @@ slip_radio_cmd_handler(const uint8_t *data, int len) /* this is just a test so far... just to see if it works */ uip_buf[0] = '!'; uip_buf[1] = 'M'; - for(i = 0; i < 8; i++) { + for(i = 0; i < UIP_LLADDR_LEN; i++) { uip_buf[2 + i] = uip_lladdr.addr[i]; } uip_len = 10; diff --git a/os/net/ipv6/uip-ds6.c b/os/net/ipv6/uip-ds6.c index 6dd178dc8..cadb26551 100644 --- a/os/net/ipv6/uip-ds6.c +++ b/os/net/ipv6/uip-ds6.c @@ -553,8 +553,6 @@ uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst) void uip_ds6_set_addr_iid(uip_ipaddr_t *ipaddr, uip_lladdr_t *lladdr) { - /* We consider only links with IEEE EUI-64 identifier or - * IEEE 48-bit MAC addresses */ #if (UIP_LLADDR_LEN == 8) memcpy(ipaddr->u8 + 8, lladdr, UIP_LLADDR_LEN); ipaddr->u8[8] ^= 0x02; @@ -564,11 +562,19 @@ uip_ds6_set_addr_iid(uip_ipaddr_t *ipaddr, uip_lladdr_t *lladdr) ipaddr->u8[12] = 0xfe; memcpy(ipaddr->u8 + 13, (uint8_t *)lladdr + 3, 3); ipaddr->u8[8] ^= 0x02; +#elif (UIP_LLADDR_LEN == 2) + /* derive IID as per RFC 6282 */ + ipaddr->u8[8 + 0] = 0x00; + ipaddr->u8[8 + 1] = 0x00; + ipaddr->u8[8 + 2] = 0x00; + ipaddr->u8[8 + 3] = 0xFF; + ipaddr->u8[8 + 4] = 0xFE; + ipaddr->u8[8 + 5] = 0x00; + memcpy(ipaddr->u8 + 8 + 6, lladdr, UIP_LLADDR_LEN); #else -#error uip-ds6.c cannot build interface address when UIP_LLADDR_LEN is not 6 or 8 +#error uip-ds6.c cannot build interface address when UIP_LLADDR_LEN is not 6, 8, or 2 #endif } - /*---------------------------------------------------------------------------*/ void uip_ds6_set_lladdr_from_iid(uip_lladdr_t *lladdr, const uip_ipaddr_t *ipaddr) @@ -576,8 +582,10 @@ uip_ds6_set_lladdr_from_iid(uip_lladdr_t *lladdr, const uip_ipaddr_t *ipaddr) #if (UIP_LLADDR_LEN == 8) memcpy(lladdr, ipaddr->u8 + 8, UIP_LLADDR_LEN); lladdr->addr[0] ^= 0x02; +#elif (UIP_LLADDR_LEN == 2) + memcpy(lladdr, ipaddr->u8 + 6, UIP_LLADDR_LEN); #else -#error uip-ds6.c cannot build lladdr address when UIP_LLADDR_LEN is not 8 +#error uip-ds6.c cannot build lladdr address when UIP_LLADDR_LEN is not 8 or 2 #endif } diff --git a/os/net/ipv6/uip.h b/os/net/ipv6/uip.h index 7751b8fc3..9f5eb159d 100755 --- a/os/net/ipv6/uip.h +++ b/os/net/ipv6/uip.h @@ -81,6 +81,7 @@ #include "net/ipv6/uipopt.h" #include "net/ipv6/uipbuf.h" +#include "net/linkaddr.h" /* For memcmp */ #include @@ -107,14 +108,16 @@ typedef uip_ip4addr_t uip_ipaddr_t; /*---------------------------------------------------------------------------*/ +#define UIP_802154_SHORTADDR_LEN 2 +#define UIP_802154_LONGADDR_LEN 8 /** \brief 16 bit 802.15.4 address */ typedef struct uip_802154_shortaddr { - uint8_t addr[2]; + uint8_t addr[UIP_802154_SHORTADDR_LEN]; } uip_802154_shortaddr; /** \brief 64 bit 802.15.4 address */ typedef struct uip_802154_longaddr { - uint8_t addr[8]; + uint8_t addr[UIP_802154_LONGADDR_LEN]; } uip_802154_longaddr; /** \brief 802.11 address */ @@ -134,11 +137,15 @@ typedef struct uip_eth_addr { #if UIP_CONF_LL_802154 /** \brief 802.15.4 address */ +#if LINKADDR_SIZE == UIP_802154_LONGADDR_LEN typedef uip_802154_longaddr uip_lladdr_t; -#define UIP_802154_SHORTADDR_LEN 2 -#define UIP_802154_LONGADDR_LEN 8 +#elif LINKADDR_SIZE == UIP_802154_SHORTADDR_LEN +typedef uip_802154_shortaddr uip_lladdr_t; +#else /* LINKADDR_SIZE == 8 */ +#error unsupported configuration of LINKADDR_SIZE +#endif /* LINKADDR_SIZE == 8 */ /** \brief Link layer address length */ -#define UIP_LLADDR_LEN UIP_802154_LONGADDR_LEN +#define UIP_LLADDR_LEN LINKADDR_SIZE #else /*UIP_CONF_LL_802154*/ #if UIP_CONF_LL_80211 /** \brief 802.11 address */ diff --git a/os/services/rpl-border-router/embedded/slip-bridge.c b/os/services/rpl-border-router/embedded/slip-bridge.c index c40447d7f..d1f97339d 100644 --- a/os/services/rpl-border-router/embedded/slip-bridge.c +++ b/os/services/rpl-border-router/embedded/slip-bridge.c @@ -95,7 +95,7 @@ slip_input_callback(void) int j; /* this is just a test so far... just to see if it works */ uip_buf[0] = '!'; - for(j = 0; j < 8; j++) { + for(j = 0; j < UIP_LLADDR_LEN; j++) { uip_buf[2 + j * 2] = hexchar[uip_lladdr.addr[j] >> 4]; uip_buf[3 + j * 2] = hexchar[uip_lladdr.addr[j] & 15]; } diff --git a/os/services/rpl-border-router/native/border-router-cmds.c b/os/services/rpl-border-router/native/border-router-cmds.c index bea6a5e2d..aa0d44710 100644 --- a/os/services/rpl-border-router/native/border-router-cmds.c +++ b/os/services/rpl-border-router/native/border-router-cmds.c @@ -183,7 +183,7 @@ border_router_cmd_handler(const uint8_t *data, int len) /* this is just a test so far... just to see if it works */ buf[0] = '!'; buf[1] = 'M'; - for(j = 0; j < 8; j++) { + for(j = 0; j < UIP_LLADDR_LEN; j++) { buf[2 + j * 2] = hexchar[uip_lladdr.addr[j] >> 4]; buf[3 + j * 2] = hexchar[uip_lladdr.addr[j] & 15]; } diff --git a/os/sys/log.c b/os/sys/log.c index 90709ec5f..05613e5c6 100644 --- a/os/sys/log.c +++ b/os/sys/log.c @@ -155,7 +155,11 @@ log_lladdr_compact(const linkaddr_t *lladdr) if(lladdr == NULL || linkaddr_cmp(lladdr, &linkaddr_null)) { LOG_OUTPUT("LL-NULL"); } else { +#if LINKADDR_SIZE == 8 LOG_OUTPUT("LL-%04x", UIP_HTONS(lladdr->u16[LINKADDR_SIZE/2-1])); +#elif LINKADDR_SIZE == 2 + LOG_OUTPUT("LL-%04x", UIP_HTONS(lladdr->u16)); +#endif } } /*---------------------------------------------------------------------------*/ From 4ba95b0768e4389cca83336efac0beb3838f553a Mon Sep 17 00:00:00 2001 From: kkrentz Date: Sat, 12 May 2018 02:42:30 -0700 Subject: [PATCH 124/129] uip-ds6.c: Compacted code for deriving IIDs from short addresses --- os/net/ipv6/uip-ds6.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/os/net/ipv6/uip-ds6.c b/os/net/ipv6/uip-ds6.c index cadb26551..879f47881 100644 --- a/os/net/ipv6/uip-ds6.c +++ b/os/net/ipv6/uip-ds6.c @@ -91,6 +91,7 @@ static uip_ds6_maddr_t *locmaddr; static uip_ds6_aaddr_t *locaaddr; #endif /* UIP_DS6_AADDR_NB */ static uip_ds6_prefix_t *locprefix; +static const uint8_t iid_prefix[] = { 0x00, 0x00 , 0x00 , 0xff , 0xfe , 0x00 }; /*---------------------------------------------------------------------------*/ void @@ -564,12 +565,7 @@ uip_ds6_set_addr_iid(uip_ipaddr_t *ipaddr, uip_lladdr_t *lladdr) ipaddr->u8[8] ^= 0x02; #elif (UIP_LLADDR_LEN == 2) /* derive IID as per RFC 6282 */ - ipaddr->u8[8 + 0] = 0x00; - ipaddr->u8[8 + 1] = 0x00; - ipaddr->u8[8 + 2] = 0x00; - ipaddr->u8[8 + 3] = 0xFF; - ipaddr->u8[8 + 4] = 0xFE; - ipaddr->u8[8 + 5] = 0x00; + memcpy(ipaddr->u8 + 8, iid_prefix, 6); memcpy(ipaddr->u8 + 8 + 6, lladdr, UIP_LLADDR_LEN); #else #error uip-ds6.c cannot build interface address when UIP_LLADDR_LEN is not 6, 8, or 2 From b13d1bc526925e20af93ef7b6ca07143f913f903 Mon Sep 17 00:00:00 2001 From: kkrentz Date: Tue, 24 Apr 2018 07:34:43 -0700 Subject: [PATCH 125/129] AES-128: Removed unused function --- os/lib/aes-128.c | 10 ---------- os/lib/aes-128.h | 5 ----- 2 files changed, 15 deletions(-) diff --git a/os/lib/aes-128.c b/os/lib/aes-128.c index 98e115c3f..3b0082e7c 100644 --- a/os/lib/aes-128.c +++ b/os/lib/aes-128.c @@ -166,16 +166,6 @@ encrypt(uint8_t *state) } } /*---------------------------------------------------------------------------*/ -void -aes_128_set_padded_key(uint8_t *key, uint8_t key_len) -{ - uint8_t block[AES_128_BLOCK_SIZE]; - - memset(block, 0, AES_128_BLOCK_SIZE); - memcpy(block, key, key_len); - AES_128.set_key(block); -} -/*---------------------------------------------------------------------------*/ const struct aes_128_driver aes_128_driver = { set_key, encrypt diff --git a/os/lib/aes-128.h b/os/lib/aes-128.h index 458b93915..e003c2b25 100644 --- a/os/lib/aes-128.h +++ b/os/lib/aes-128.h @@ -67,11 +67,6 @@ struct aes_128_driver { void (* encrypt)(uint8_t *plaintext_and_result); }; -/** - * \brief Pads the key with zeroes before calling AES_128.set_key - */ -void aes_128_set_padded_key(uint8_t *key, uint8_t key_len); - extern const struct aes_128_driver AES_128; #endif /* AES_128_H_ */ From 1c54e8d7d762c6fa67ff7ebcc1a9f51464dc8dbc Mon Sep 17 00:00:00 2001 From: kkrentz Date: Tue, 24 Apr 2018 09:02:08 -0700 Subject: [PATCH 126/129] packetbuf: Removed attribute KEY_SOURCE_BYTES_0_1 --- os/net/mac/framer/framer-802154.c | 2 -- os/net/packetbuf.h | 1 - 2 files changed, 3 deletions(-) diff --git a/os/net/mac/framer/framer-802154.c b/os/net/mac/framer/framer-802154.c index 7122c5ccd..b4c24da19 100644 --- a/os/net/mac/framer/framer-802154.c +++ b/os/net/mac/framer/framer-802154.c @@ -171,7 +171,6 @@ framer_802154_setup_params(packetbuf_attr_t (*get_attr)(uint8_t type), #if LLSEC802154_USES_EXPLICIT_KEYS params->aux_hdr.security_control.key_id_mode = get_attr(PACKETBUF_ATTR_KEY_ID_MODE); params->aux_hdr.key_index = get_attr(PACKETBUF_ATTR_KEY_INDEX); - params->aux_hdr.key_source.u16[0] = get_attr(PACKETBUF_ATTR_KEY_SOURCE_BYTES_0_1); #endif /* LLSEC802154_USES_EXPLICIT_KEYS */ #else params->fcf.security_enabled = 0; @@ -273,7 +272,6 @@ parse(void) #if LLSEC802154_USES_EXPLICIT_KEYS packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, frame.aux_hdr.security_control.key_id_mode); packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, frame.aux_hdr.key_index); - packetbuf_set_attr(PACKETBUF_ATTR_KEY_SOURCE_BYTES_0_1, frame.aux_hdr.key_source.u16[0]); #endif /* LLSEC802154_USES_EXPLICIT_KEYS */ } #endif /* LLSEC802154_USES_AUX_HEADER */ diff --git a/os/net/packetbuf.h b/os/net/packetbuf.h index 39ce4a467..20e071474 100644 --- a/os/net/packetbuf.h +++ b/os/net/packetbuf.h @@ -236,7 +236,6 @@ enum { #if LLSEC802154_USES_EXPLICIT_KEYS PACKETBUF_ATTR_KEY_ID_MODE, PACKETBUF_ATTR_KEY_INDEX, - PACKETBUF_ATTR_KEY_SOURCE_BYTES_0_1, #endif /* LLSEC802154_USES_EXPLICIT_KEYS */ /* Scope 2 attributes: used between end-to-end nodes. */ From 83b028af289ccddbd7d60078887559639aa058fb Mon Sep 17 00:00:00 2001 From: kkrentz Date: Sat, 12 May 2018 03:59:20 -0700 Subject: [PATCH 127/129] linkaddr: Removed linkaddr_extended_t --- os/net/linkaddr.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/os/net/linkaddr.h b/os/net/linkaddr.h index 6f7380218..7926550b1 100644 --- a/os/net/linkaddr.h +++ b/os/net/linkaddr.h @@ -70,11 +70,6 @@ typedef union { #endif /* LINKADDR_SIZE == 2 */ } linkaddr_t; -typedef union { - uint8_t u8[8]; - uint16_t u16[4]; -} linkaddr_extended_t; - /** * \brief Copy a link-layer address * \param dest The destination From fd379cd50b7cf65f96a3f4d88066f6391152aff2 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 15:16:26 +0100 Subject: [PATCH 128/129] Add missing case statement --- tools/tools-utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/tools-utils.c b/tools/tools-utils.c index 6ad0a9365..50a50c025 100644 --- a/tools/tools-utils.c +++ b/tools/tools-utils.c @@ -104,6 +104,7 @@ select_baudrate(int baudrate) { return B115200; #endif #ifdef B230400 + case 230400: return B230400; #endif #ifdef B460800 From 32bdb70afaa0e6f97e09467e2206d28a5716a464 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Sat, 12 May 2018 17:04:41 +0100 Subject: [PATCH 129/129] Extend usage string --- Makefile.include | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile.include b/Makefile.include index 1d06acd23..4de7e7dbb 100644 --- a/Makefile.include +++ b/Makefile.include @@ -403,6 +403,11 @@ usage: @echo " clean Removes all compiled files for TARGET" @echo " distclean Removes all compiled files for all TARGETs" @echo " viewconf Prints Contiki-NG build configuration for TARGET" + @echo " %.flashprof Shows a Flash/ROM profile of a given firmware (e.g. hello-world.flashprof)" + @echo " %.ramprof Shows a RAM profile of a given firmware (e.g. hello-world.ramprof)" + @echo " %.o Produces an object file from a given source file (e.g. hello-world.o)" + @echo " %.e Produces the pre-processed version of a given source file (e.g. hello-world.e)" + @echo " %.s Produces an assembly file from a given source file (e.g. hello-world.s)" help: usage

&YTNNEplw)aD0|;sK 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 literal 0 HcmV?d00001 From 81f337cd772392e85ad0b9134bb211583e109395 Mon Sep 17 00:00:00 2001 From: YK Date: Mon, 23 Apr 2018 11:16:59 +0800 Subject: [PATCH 079/129] Update README.md for IBM Watson IoT Platform Update README.md to show how to enable TLS optional to use IBM Watson IoT Platform for cc26xx-web-demo --- examples/platform-specific/cc26xx/cc26xx-web-demo/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md b/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md index 67b28ba93..315407fd8 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md @@ -166,3 +166,9 @@ the state of the LED. Bear in mind that, even though the topic suggests that messages are of json format, they are in fact not. This was done in order to avoid linking a json parser into the firmware. + +IBM Watson IoT Platform +---------------------------- +To use IBM Watson IoT Platform, you have to go to SECURITY tab of Device page to select "TLS Optional". This step is critical. If you don't do this, you need to use TLS for connection and default cc26xx-web-demo won't work. + +![IBM Watson IoT Platform TLS Optional Configuration](img/ibm-watson-iot-platform-tls-optional.png) From 3bd6c67e64020df8311148c5bb15e1b910bee2e0 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Sun, 22 Apr 2018 00:33:31 -0700 Subject: [PATCH 080/129] RPL native border router: use logging module --- .../native/border-router-cmds.c | 20 ++++++++++--------- .../native/border-router-mac.c | 20 +++++++++---------- .../native/border-router-native.c | 17 +++++++++------- .../rpl-border-router/native/tun-bridge.c | 11 ++++++---- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/os/services/rpl-border-router/native/border-router-cmds.c b/os/services/rpl-border-router/native/border-router-cmds.c index 9d0e2eb9f..bea6a5e2d 100644 --- a/os/services/rpl-border-router/native/border-router-cmds.c +++ b/os/services/rpl-border-router/native/border-router-cmds.c @@ -46,8 +46,11 @@ #include "shell.h" #include -#define DEBUG DEBUG_NONE -#include "net/ipv6/uip-debug.h" +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "BR" +#define LOG_LEVEL LOG_LEVEL_NONE uint8_t command_context; @@ -115,7 +118,7 @@ border_router_cmd_handler(const uint8_t *data, int len) { /* handle global repair, etc here */ if(data[0] == '!') { - PRINTF("Got configuration message of type %c\n", data[1]); + LOG_DBG("Got configuration message of type %c\n", data[1]); if(command_context == CMD_CONTEXT_STDIO) { switch(data[1]) { case 'G': @@ -151,7 +154,7 @@ border_router_cmd_handler(const uint8_t *data, int len) /* We need to know that this is from the slip-radio here. */ switch(data[1]) { case 'M': - PRINTF("Setting MAC address\n"); + LOG_DBG("Setting MAC address\n"); border_router_set_mac(&data[2]); return 1; case 'V': @@ -163,7 +166,7 @@ border_router_cmd_handler(const uint8_t *data, int len) } return 1; case 'R': - PRINTF("Packet data report for sid:%d st:%d tx:%d\n", + LOG_DBG("Packet data report for sid:%d st:%d tx:%d\n", data[2], data[3], data[4]); packet_sent(data[2], data[3], data[4]); return 1; @@ -172,7 +175,7 @@ border_router_cmd_handler(const uint8_t *data, int len) } } } else if(data[0] == '?') { - PRINTF("Got request message of type %c\n", data[1]); + LOG_DBG("Got request message of type %c\n", data[1]); if(data[1] == 'M' && command_context == CMD_CONTEXT_STDIO) { uint8_t buf[20]; char *hexchar = "0123456789abcdef"; @@ -226,15 +229,14 @@ PROCESS_THREAD(border_router_cmd_process, ev, data) { static struct pt shell_input_pt; PROCESS_BEGIN(); - PRINTF("Started br-cmd process\n"); shell_init(); while(1) { PROCESS_YIELD(); if(ev == serial_line_event_message && data != NULL) { - PRINTF("Got serial data!!! %s of len: %lu\n", - (char *)data, strlen((char *)data)); + LOG_DBG("Got serial data!!! %s of len: %u\n", + (char *)data, (unsigned)strlen((char *)data)); command_context = CMD_CONTEXT_STDIO; if(cmd_input(data, strlen((char *)data))) { /* Commnand executed - all is fine */ diff --git a/os/services/rpl-border-router/native/border-router-mac.c b/os/services/rpl-border-router/native/border-router-mac.c index bcfb829b7..83debbab6 100644 --- a/os/services/rpl-border-router/native/border-router-mac.c +++ b/os/services/rpl-border-router/native/border-router-mac.c @@ -44,13 +44,11 @@ #include "border-router.h" #include -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#else -#define PRINTF(...) -#endif +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "BR" +#define LOG_LEVEL LOG_LEVEL_NONE #define MAX_CALLBACKS 16 static int callback_pos; @@ -76,7 +74,7 @@ packet_sent(uint8_t sessionid, uint8_t status, uint8_t tx) packetbuf_attr_copyfrom(callback->attrs, callback->addrs); mac_call_sent_callback(callback->cback, callback->ptr, status, tx); } else { - PRINTF("*** ERROR: too high session id %d\n", sessionid); + LOG_ERR("Session id to high (%d)\n", sessionid); } } /*---------------------------------------------------------------------------*/ @@ -117,7 +115,7 @@ send_packet(mac_callback_t sent, void *ptr) if(NETSTACK_FRAMER.create() < 0) { /* Failed to allocate space for headers */ - PRINTF("br-rdc: send failed, too large header\n"); + LOG_WARN("br-rdc: send failed, too large header\n"); mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 1); } else { /* here we send the data over SLIP to the radio-chip */ @@ -126,7 +124,7 @@ send_packet(mac_callback_t sent, void *ptr) size = packetutils_serialize_atts(&buf[3], sizeof(buf) - 3); #endif if(size < 0 || size + packetbuf_totlen() + 3 > sizeof(buf)) { - PRINTF("br-rdc: send failed, too large header\n"); + LOG_WARN("br-rdc: send failed, too large header\n"); mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 1); } else { sid = setup_callback(sent, ptr); @@ -147,7 +145,7 @@ static void packet_input(void) { if(NETSTACK_FRAMER.parse() < 0) { - PRINTF("br-rdc: failed to parse %u\n", packetbuf_datalen()); + LOG_DBG("br-rdc: failed to parse %u\n", packetbuf_datalen()); } else { NETSTACK_NETWORK.input(); } diff --git a/os/services/rpl-border-router/native/border-router-native.c b/os/services/rpl-border-router/native/border-router-native.c index 3da0ef000..2adebe121 100644 --- a/os/services/rpl-border-router/native/border-router-native.c +++ b/os/services/rpl-border-router/native/border-router-native.c @@ -47,8 +47,11 @@ #include "border-router.h" #include "border-router-cmds.h" -#define DEBUG DEBUG_FULL -#include "net/ipv6/uip-debug.h" +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "BR" +#define LOG_LEVEL LOG_LEVEL_INFO #include @@ -106,7 +109,7 @@ PROCESS_THREAD(border_router_process, ev, data) process_start(&border_router_cmd_process, NULL); - PRINTF("RPL-Border router started\n"); + LOG_INFO("RPL-Border router started\n"); slip_config_handle_arguments(contiki_argc, contiki_argv); @@ -123,12 +126,12 @@ PROCESS_THREAD(border_router_process, ev, data) uip_ipaddr_t prefix; if(uiplib_ipaddrconv((const char *)slip_config_ipaddr, &prefix)) { - PRINTF("Setting prefix "); - PRINT6ADDR(&prefix); - PRINTF("\n"); + LOG_INFO("Setting prefix "); + LOG_INFO_6ADDR(&prefix); + LOG_INFO_("\n"); set_prefix_64(&prefix); } else { - PRINTF("Parse error: %s\n", slip_config_ipaddr); + LOG_ERR("Parse error: %s\n", slip_config_ipaddr); exit(0); } } diff --git a/os/services/rpl-border-router/native/tun-bridge.c b/os/services/rpl-border-router/native/tun-bridge.c index a60819b26..f321577b3 100644 --- a/os/services/rpl-border-router/native/tun-bridge.c +++ b/os/services/rpl-border-router/native/tun-bridge.c @@ -50,8 +50,11 @@ #include #include -#define DEBUG DEBUG_FULL -#include "net/ipv6/uip-debug.h" +/*---------------------------------------------------------------------------*/ +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "BR" +#define LOG_LEVEL LOG_LEVEL_NONE #ifdef linux #include @@ -202,7 +205,7 @@ tun_init() slip_init(); - PRINTF("Opening tun interface:%s\n", slip_config_tundev); + LOG_INFO("Opening tun interface:%s\n", slip_config_tundev); tunfd = tun_alloc(slip_config_tundev); @@ -251,7 +254,7 @@ init(void) static int output(void) { - PRINTF("SUT: %u\n", uip_len); + LOG_DBG("SUT: %u\n", uip_len); if(uip_len > 0) { return tun_output(&uip_buf[UIP_LLH_LEN], uip_len); } From 01a4b38fc8372a485bff4a5cb0ba82ca8f860aa2 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Wed, 25 Apr 2018 02:43:01 +0200 Subject: [PATCH 081/129] uiplib: ensure string is null-terminated when printing unspecified address --- os/net/ipv6/uiplib.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/os/net/ipv6/uiplib.c b/os/net/ipv6/uiplib.c index 693626c87..afe6de42b 100644 --- a/os/net/ipv6/uiplib.c +++ b/os/net/ipv6/uiplib.c @@ -250,9 +250,11 @@ uiplib_ipaddr_snprint(char *buf, size_t size, const uip_ipaddr_t *addr) } } - if(n >= size - 1) { - buf[size - 1] = '\0'; - } + /* + * Make sure the output string is always null-terminated. + */ + buf[MIN(n, size - 1)] = '\0'; + return n; } /*---------------------------------------------------------------------------*/ From ab2b1f46936528ebe310006699591b1f821bd06f Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 24 Apr 2018 09:04:01 -0700 Subject: [PATCH 082/129] Main: always log 802.15.4 default channel --- os/contiki-main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/os/contiki-main.c b/os/contiki-main.c index 8f9c3cd0b..b9aea5cd6 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -91,11 +91,11 @@ main(void) LOG_INFO("- Net: %s\n", NETSTACK_NETWORK.name); LOG_INFO("- MAC: %s\n", NETSTACK_MAC.name); LOG_INFO("- 802.15.4 PANID: 0x%04x\n", IEEE802154_PANID); -#if MAC_CONF_WITH_CSMA - LOG_INFO("- 802.15.4 Channel: %u\n", IEEE802154_DEFAULT_CHANNEL); -#elif MAC_CONF_WITH_TSCH +#if MAC_CONF_WITH_TSCH LOG_INFO("- 802.15.4 TSCH default hopping sequence length: %u\n", (unsigned)sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)); -#endif +#else /* MAC_CONF_WITH_TSCH */ + LOG_INFO("- 802.15.4 Default channel: %u\n", IEEE802154_DEFAULT_CHANNEL); +#endif /* MAC_CONF_WITH_TSCH */ netstack_init(); From a099bda05882a36366f98eb58c49e9bece37f959 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Tue, 24 Apr 2018 09:03:06 -0700 Subject: [PATCH 083/129] Added jool-start.sh script --- tools/ip64/jool-start.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100755 tools/ip64/jool-start.sh diff --git a/tools/ip64/jool-start.sh b/tools/ip64/jool-start.sh new file mode 100755 index 000000000..b9c0c9850 --- /dev/null +++ b/tools/ip64/jool-start.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +defaultInterface=$(route | grep default | awk '{print $(NF)}') +myIP=$(ifconfig $defaultInterface | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}') +echo "Configuring jool for $myIP" + +sudo sysctl -w net.ipv4.conf.all.forwarding=1 +sudo sysctl -w net.ipv6.conf.all.forwarding=1 + +sudo /sbin/modprobe jool pool6=64:ff9b::/96 disabled + +# Assuming that we are on this IP +sudo jool -4 --add $myIP 15000-25000 +sudo jool --enable From 4da9202d22693a71568093d48773bf5a60c9cf0b Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 25 Apr 2018 01:55:53 -0700 Subject: [PATCH 084/129] Add lrwrap to login and native BR --- arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx | 4 ++-- arch/platform/jn516x/Makefile.jn516x | 4 ++-- arch/platform/sky/Makefile.common | 4 ++-- arch/platform/zoul/Makefile.zoul | 4 ++-- os/services/rpl-border-router/native/Makefile.native | 4 ++-- tools/docker/Dockerfile | 2 +- tools/vagrant/bootstrap.sh | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx index e72954c17..ef7c47443 100644 --- a/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx +++ b/arch/cpu/cc26xx-cc13xx/Makefile.cc26xx-cc13xx @@ -93,10 +93,10 @@ ifeq ($(HOST_OS),Windows) SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-windows else ifeq ($(HOST_OS),Darwin) - SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-macos + SERIALDUMP ?= rlwrap $(CONTIKI)/tools/sky/serialdump-macos else # Else assume Linux - SERIALDUMP ?= $(CONTIKI)/tools/sky/serialdump-linux + SERIALDUMP ?= rlwrap $(CONTIKI)/tools/sky/serialdump-linux endif endif diff --git a/arch/platform/jn516x/Makefile.jn516x b/arch/platform/jn516x/Makefile.jn516x index 9f7a31adf..bb40b5638 100644 --- a/arch/platform/jn516x/Makefile.jn516x +++ b/arch/platform/jn516x/Makefile.jn516x @@ -180,12 +180,12 @@ else ifeq ($(HOST_OS),Darwin) USBDEVPREFIX= USBDEVBASENAME=/dev/tty.usbserial- - SERIALDUMP ?= $(CONTIKI)/tools/jn516x/serialdump-macos + SERIALDUMP ?= rlwrap $(CONTIKI)/tools/jn516x/serialdump-macos else # Else we assume Linux USBDEVPREFIX= USBDEVBASENAME=/dev/ttyUSB - SERIALDUMP ?= $(CONTIKI)/tools/jn516x/serialdump-linux + SERIALDUMP ?= rlwrap $(CONTIKI)/tools/jn516x/serialdump-linux endif endif diff --git a/arch/platform/sky/Makefile.common b/arch/platform/sky/Makefile.common index 081ffaa9f..3d688b573 100644 --- a/arch/platform/sky/Makefile.common +++ b/arch/platform/sky/Makefile.common @@ -54,7 +54,7 @@ else ifeq ($(HOST_OS),Darwin) ifndef MOTELIST USBDEVPREFIX= - SERIALDUMP = $(CONTIKI)/tools/sky/serialdump-macos + SERIALDUMP = rlwrap $(CONTIKI)/tools/sky/serialdump-macos MOTELIST = $(CONTIKI)/tools/sky/motelist-macos TMOTE_BSL_FILE = tmote-bsl-linux TMOTE_BSL=$(if $(wildcard $(CONTIKI)/tools/sky/$(TMOTE_BSL_FILE)),1,0) @@ -75,7 +75,7 @@ else # Else we assume Linux ifndef MOTELIST USBDEVPREFIX= - SERIALDUMP = $(CONTIKI)/tools/sky/serialdump-linux + SERIALDUMP = rlwrap $(CONTIKI)/tools/sky/serialdump-linux MOTELIST = $(CONTIKI)/tools/sky/motelist-linux TMOTE_BSL_FILE = tmote-bsl-linux TMOTE_BSL=$(if $(wildcard $(CONTIKI)/tools/sky/$(TMOTE_BSL_FILE)),1,0) diff --git a/arch/platform/zoul/Makefile.zoul b/arch/platform/zoul/Makefile.zoul index 586a74ae2..e7e4af709 100644 --- a/arch/platform/zoul/Makefile.zoul +++ b/arch/platform/zoul/Makefile.zoul @@ -56,11 +56,11 @@ ifeq ($(HOST_OS),Darwin) USBDEVPREFIX= MOTELIST := $(CONTIKI)/tools/zolertia/motelist-zolertia-macos MOTES := $(shell $(MOTELIST) -c 2>&- | cut -f 2 -d ,) - SERIALDUMP := $(CONTIKI)/tools/sky/serialdump-macos + SERIALDUMP := rlwrap $(CONTIKI)/tools/sky/serialdump-macos else ### If we are not running under Mac, we assume Linux USBDEVPREFIX= - SERIALDUMP := $(CONTIKI)/tools/sky/serialdump-linux + SERIALDUMP := rlwrap $(CONTIKI)/tools/sky/serialdump-linux MOTELIST := $(CONTIKI)/tools/zolertia/motelist-zolertia MOTES := $(shell $(MOTELIST) -b $(MOTELIST_ZOLERTIA) -c 2>&- | cut -f 2 -d , | \ perl -ne 'print $$1 . " " if(m-(/dev/\w+)-);') diff --git a/os/services/rpl-border-router/native/Makefile.native b/os/services/rpl-border-router/native/Makefile.native index a225e1666..3f758c1be 100644 --- a/os/services/rpl-border-router/native/Makefile.native +++ b/os/services/rpl-border-router/native/Makefile.native @@ -7,7 +7,7 @@ MAKE_NET = MAKE_NET_IPV6 PREFIX ?= fd00::1/64 connect-router: border-router.native - sudo ./border-router.native $(PREFIX) + sudo rlwrap ./border-router.native $(PREFIX) connect-router-cooja: border-router.native - sudo ./border-router.native -a localhost $(PREFIX) + sudo rlwrap ./border-router.native -a localhost $(PREFIX) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index d8e9c0a79..b223ddaa0 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -4,7 +4,7 @@ FROM 32bit/ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ build-essential doxygen git wget unzip python-serial \ - default-jdk ant srecord iputils-tracepath && \ + default-jdk ant srecord iputils-tracepath rlwrap && \ apt-get clean # Install ARM toolchain diff --git a/tools/vagrant/bootstrap.sh b/tools/vagrant/bootstrap.sh index 996ffb12e..c6cbd3d3c 100755 --- a/tools/vagrant/bootstrap.sh +++ b/tools/vagrant/bootstrap.sh @@ -8,7 +8,7 @@ sudo apt install -y --no-install-recommends \ # Tools sudo apt-get install -y --no-install-recommends \ - build-essential doxygen git wget unzip python-serial \ + build-essential doxygen git wget unzip python-serial rlwrap \ default-jdk ant srecord python-pip iputils-tracepath uncrustify python-magic sudo apt-get clean sudo python2 -m pip install intelhex From 484e9521ee1b5f08c7182be1f91df9f0af3c05fe Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Thu, 26 Apr 2018 14:39:30 +0100 Subject: [PATCH 085/129] Change the default channel This commit changes the cc26xx web demo to default to channel 26, which is the default everywhere else. --- .../platform-specific/cc26xx/cc26xx-web-demo/project-conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h index c5078bf38..40a1e8262 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/project-conf.h @@ -33,7 +33,7 @@ /*---------------------------------------------------------------------------*/ /* Change to match your configuration */ #define IEEE802154_CONF_PANID 0xABCD -#define RF_CORE_CONF_CHANNEL 25 +#define RF_CORE_CONF_CHANNEL 26 #define RF_BLE_CONF_ENABLED 1 /*---------------------------------------------------------------------------*/ From 274a5daa7ddd7d7df0a010fa97f816c10433cfb8 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 27 Apr 2018 01:43:19 +0200 Subject: [PATCH 086/129] Updated users of SLIP to respect UIP_LLH_LEN --- examples/slip-radio/slip-radio.c | 9 +++--- os/services/ip64/ip64-slip-interface.c | 20 +++++------- .../rpl-border-router/embedded/slip-bridge.c | 32 +++++++++++-------- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/examples/slip-radio/slip-radio.c b/examples/slip-radio/slip-radio.c index 21779a3dc..b39032d96 100644 --- a/examples/slip-radio/slip-radio.c +++ b/examples/slip-radio/slip-radio.c @@ -187,8 +187,8 @@ slip_radio_cmd_handler(const uint8_t *data, int len) } return 1; } - } else if(uip_buf[0] == '?') { - LOG_DBG("Got request message of type %c\n", uip_buf[1]); + } else if(data[0] == '?') { + LOG_DBG("Got request message of type %c\n", data[1]); if(data[1] == 'M') { /* this is just a test so far... just to see if it works */ uip_buf[0] = '!'; @@ -226,8 +226,9 @@ slip_radio_cmd_handler(const uint8_t *data, int len) static void slip_input_callback(void) { - LOG_DBG("SR-SIN: %u '%c%c'\n", uip_len, uip_buf[0], uip_buf[1]); - if(!cmd_input(uip_buf, uip_len)) { + LOG_DBG("SR-SIN: %u '%c%c'\n", uip_len, + uip_buf[UIP_LLH_LEN], uip_buf[UIP_LLH_LEN + 1]); + if(!cmd_input(&uip_buf[UIP_LLH_LEN], uip_len)) { cmd_send((uint8_t *)"EUnknown command", 16); } uip_clear_buf(); diff --git a/os/services/ip64/ip64-slip-interface.c b/os/services/ip64/ip64-slip-interface.c index 7ad4d4789..10422f2c7 100644 --- a/os/services/ip64/ip64-slip-interface.c +++ b/os/services/ip64/ip64-slip-interface.c @@ -57,24 +57,24 @@ static void input_callback(void) { /*PRINTF("SIN: %u\n", uip_len);*/ - if(uip_buf[0] == '!') { - PRINTF("Got configuration message of type %c\n", uip_buf[1]); + if(uip_buf[UIP_LLH_LEN] == '!') { + PRINTF("Got configuration message of type %c\n", uip_buf[UIP_LLH_LEN + 1]); uip_clear_buf(); #if 0 - if(uip_buf[1] == 'P') { + if(uip_buf[UIP_LLH_LEN + 1] == 'P') { uip_ipaddr_t prefix; /* Here we set a prefix !!! */ memset(&prefix, 0, 16); - memcpy(&prefix, &uip_buf[2], 8); + memcpy(&prefix, &uip_buf[UIP_LLH_LEN + 2], 8); PRINTF("Setting prefix "); PRINT6ADDR(&prefix); PRINTF("\n"); set_prefix_64(&prefix); } #endif - } else if(uip_buf[0] == '?') { - PRINTF("Got request message of type %c\n", uip_buf[1]); - if(uip_buf[1] == 'M') { + } else if(uip_buf[UIP_LLH_LEN] == '?') { + PRINTF("Got request message of type %c\n", uip_buf[UIP_LLH_LEN + 1]); + if(uip_buf[UIP_LLH_LEN + 1] == 'M') { const char *hexchar = "0123456789abcdef"; int j; /* this is just a test so far... just to see if it works */ @@ -84,8 +84,7 @@ input_callback(void) uip_buf[3 + j * 2] = hexchar[uip_lladdr.addr[j] & 15]; } uip_len = 18; - slip_send(); - + slip_write(uip_buf, uip_len); } uip_clear_buf(); } else { @@ -147,6 +146,3 @@ const struct uip_fallback_interface ip64_slip_interface = { init, output }; /*---------------------------------------------------------------------------*/ - - - diff --git a/os/services/rpl-border-router/embedded/slip-bridge.c b/os/services/rpl-border-router/embedded/slip-bridge.c index cb85793f0..c40447d7f 100644 --- a/os/services/rpl-border-router/embedded/slip-bridge.c +++ b/os/services/rpl-border-router/embedded/slip-bridge.c @@ -62,7 +62,7 @@ request_prefix(void) uip_buf[0] = '?'; uip_buf[1] = 'P'; uip_len = 2; - slip_send(); + slip_write(uip_buf, uip_len); uip_clear_buf(); } /*---------------------------------------------------------------------------*/ @@ -70,22 +70,27 @@ static void slip_input_callback(void) { LOG_DBG("SIN: %u\n", uip_len); - if(uip_buf[0] == '!') { - LOG_INFO("Got configuration message of type %c\n", uip_buf[1]); - uip_clear_buf(); - if(uip_buf[1] == 'P') { + if(uip_buf[UIP_LLH_LEN] == '!') { + LOG_INFO("Got configuration message of type %c\n", + uip_buf[UIP_LLH_LEN + 1]); + if(uip_buf[UIP_LLH_LEN + 1] == 'P') { uip_ipaddr_t prefix; /* Here we set a prefix !!! */ memset(&prefix, 0, 16); - memcpy(&prefix, &uip_buf[2], 8); + memcpy(&prefix, &uip_buf[UIP_LLH_LEN + 2], 8); + + uip_clear_buf(); + LOG_INFO("Setting prefix "); LOG_INFO_6ADDR(&prefix); LOG_INFO_("\n"); set_prefix_64(&prefix); } - } else if(uip_buf[0] == '?') { - LOG_INFO("Got request message of type %c\n", uip_buf[1]); - if(uip_buf[1] == 'M') { + uip_clear_buf(); + + } else if(uip_buf[UIP_LLH_LEN] == '?') { + LOG_INFO("Got request message of type %c\n", uip_buf[UIP_LLH_LEN + 1]); + if(uip_buf[UIP_LLH_LEN + 1] == 'M') { char *hexchar = "0123456789abcdef"; int j; /* this is just a test so far... just to see if it works */ @@ -95,13 +100,14 @@ slip_input_callback(void) uip_buf[3 + j * 2] = hexchar[uip_lladdr.addr[j] & 15]; } uip_len = 18; - slip_send(); + slip_write(uip_buf, uip_len); } uip_clear_buf(); + } else { + /* Save the last sender received over SLIP to avoid bouncing the + packet back if no route is found */ + uip_ipaddr_copy(&last_sender, &UIP_IP_BUF->srcipaddr); } - /* Save the last sender received over SLIP to avoid bouncing the - packet back if no route is found */ - uip_ipaddr_copy(&last_sender, &UIP_IP_BUF->srcipaddr); } /*---------------------------------------------------------------------------*/ static void From 6b78522ebb667b3e98a076043f7b997d0e175204 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Thu, 26 Apr 2018 21:11:10 +0200 Subject: [PATCH 087/129] Added a periodic timer to the hello-world example --- examples/hello-world/hello-world.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/hello-world/hello-world.c b/examples/hello-world/hello-world.c index 30724140e..e6d452d9e 100644 --- a/examples/hello-world/hello-world.c +++ b/examples/hello-world/hello-world.c @@ -46,10 +46,21 @@ AUTOSTART_PROCESSES(&hello_world_process); /*---------------------------------------------------------------------------*/ PROCESS_THREAD(hello_world_process, ev, data) { + static struct etimer timer; + PROCESS_BEGIN(); - printf("Hello, world\n"); - + /* Setup a periodic timer that expires after 10 seconds. */ + etimer_set(&timer, CLOCK_SECOND * 10); + + while(1) { + printf("Hello, world\n"); + + /* Wait for the periodic timer to expire and then restart the timer. */ + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer)); + etimer_reset(&timer); + } + PROCESS_END(); } /*---------------------------------------------------------------------------*/ From 08ba4a849d16b255e907c8d514e0d3add4314409 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 27 Apr 2018 15:56:02 +0100 Subject: [PATCH 088/129] Fix the multicast example for sensortags --- examples/multicast/project-conf.h | 5 +++ .../multicast/srf06-cc26xx/module-macros.h | 34 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 examples/multicast/srf06-cc26xx/module-macros.h diff --git a/examples/multicast/project-conf.h b/examples/multicast/project-conf.h index 45fe1309e..c1bb6910e 100644 --- a/examples/multicast/project-conf.h +++ b/examples/multicast/project-conf.h @@ -54,7 +54,12 @@ #define UIP_MCAST6_ROUTE_CONF_ROUTES 1 /* Code/RAM footprint savings so that things will fit on our device */ +#ifndef NETSTACK_MAX_ROUTE_ENTRIES #define NETSTACK_MAX_ROUTE_ENTRIES 10 +#endif + +#ifndef NBR_TABLE_CONF_MAX_NEIGHBORS #define NBR_TABLE_CONF_MAX_NEIGHBORS 10 +#endif #endif /* PROJECT_CONF_H_ */ diff --git a/examples/multicast/srf06-cc26xx/module-macros.h b/examples/multicast/srf06-cc26xx/module-macros.h new file mode 100644 index 000000000..460688ebd --- /dev/null +++ b/examples/multicast/srf06-cc26xx/module-macros.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, University of Bristol - http://www.bristol.ac.uk/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +/* Code/RAM footprint savings so that things will fit on sensortags */ +#define NETSTACK_MAX_ROUTE_ENTRIES 4 +#define NBR_TABLE_CONF_MAX_NEIGHBORS 4 +#define QUEUEBUF_CONF_NUM 4 From 2996569585e3dd200c2049c9f74a422c69914d55 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Fri, 27 Apr 2018 11:59:46 -0700 Subject: [PATCH 089/129] Dockerfile: added Mosquitto --- tools/docker/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index b223ddaa0..b03aa8b32 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -4,8 +4,9 @@ FROM 32bit/ubuntu:16.04 RUN apt-get update && \ apt-get install -y --no-install-recommends \ build-essential doxygen git wget unzip python-serial \ - default-jdk ant srecord iputils-tracepath rlwrap && \ - apt-get clean + default-jdk ant srecord iputils-tracepath rlwrap \ + mosquitto mosquitto-clients \ + && apt-get clean # Install ARM toolchain RUN wget https://launchpad.net/gcc-arm-embedded/5.0/5-2015-q4-major/+download/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 && \ From 774a9285fd14abe1d8417b1d03a59f658e20b1b0 Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Fri, 27 Apr 2018 18:01:28 +0100 Subject: [PATCH 090/129] Update the CoAP section of the cc26xx web demo readme --- .../cc26xx/cc26xx-web-demo/README.md | 39 ++++++++++-------- .../cc26xx-web-demo/img/coap-resources.png | Bin 280210 -> 0 bytes 2 files changed, 22 insertions(+), 17 deletions(-) delete mode 100644 examples/platform-specific/cc26xx/cc26xx-web-demo/img/coap-resources.png diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md b/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md index 67b28ba93..6acd69b3a 100644 --- a/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md +++ b/examples/platform-specific/cc26xx/cc26xx-web-demo/README.md @@ -54,33 +54,38 @@ tab, as per the image below. CoAP Server ----------- -For this functionality to work, you will need to install the -[Copper (Cu)](https://addons.mozilla.org/en-US/firefox/addon/copper-270430/) -addon to your browser. +For this functionality to work, you will need to install a CoAP client. +You can achieve this by following the guides on how to set up your system +[in the wiki](https://github.com/contiki-ng/contiki-ng/wiki#setting-up-contiki-ng). -From the sensors tab in the 6lbr web page, click the 'coap' link in the line -corresponding to your CC26xx device. Once the addon fires up, select -".well-known/core" in the left pane and then hit the 'Get' button at the top. +You should start by sending a CoAP GET request for the `.well-known/core` +resource. If you are using libcoap's CoAP client, this can be achieved by: -![CoAP Resources](img/coap-resources.png) +``` +coap-client -m get coap://[]/.well-known/core +``` + +Adjust the above command to match the command line arguments of your CoAP +client. The Device will respond with a list of all available CoAP resources. This list -will be different between the Srf and the SensorTag. The screenshot below shows -a (partial) list of resources exported by the SensorTag CoAP server. Select -a resource on the left pane and hit 'Get' to retrieve its value. Select -`lt/g` and hit 'Post' to toggle the green LED, `lt/r` for the red one. +will be different between the various CC13x0/CC26x0 boards. -You can also use CoAP to enable/disable BLE advertisements! Select -`dev/ble_advd` and then hit the "Outgoing" button in the payload panel. Type in -the desired payload, which can be: +Send a CoAP GET request for any of those resrouces to retrieve its value. + +Send a CoAP POST to the `lt/g` or `lt/r` to toggle the green/red LED +respectively. + +You can also use CoAP to enable/disable BLE advertisements! This can be done +by sending a PUT or POST request to the `dev/ble_advd` resource. Your request +should contain the desired payload, which can be: * `mode=on|off` * `name=` * `interval=` -or a combination of both delimited with an amp. For example, you can set as -payload `mode=on&name=My CC26xx Device 4&interval=5`. Once you have set the -payload, hit either the POST or PUT button. +or a combination of the above delimited with an amp. For example, you can set +as payload `mode=on&name=My CC26xx Device 4&interval=5`. Bear in mind that you must set `name` at least once before enabling BLE advertisements. If you fail to do so, the RF will refuse to enter BLE mode and diff --git a/examples/platform-specific/cc26xx/cc26xx-web-demo/img/coap-resources.png b/examples/platform-specific/cc26xx/cc26xx-web-demo/img/coap-resources.png deleted file mode 100644 index c71c934fe8ab419f03c1ace336352b549e652eca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 280210 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